Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
84ddb681
Commit
84ddb681
authored
Jun 19, 2012
by
Richard Henderson
Committed by
Richard Henderson
Jun 19, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use synth_mult for vector multiplies vs scalar constant
From-SVN: r188786
parent
6bc0ff89
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
262 additions
and
198 deletions
+262
-198
gcc/ChangeLog
+11
-0
gcc/expmed.c
+243
-195
gcc/machmode.h
+8
-3
No files found.
gcc/ChangeLog
View file @
84ddb681
2012-06-19 Richard Henderson <rth@redhat.com>
2012-06-19 Richard Henderson <rth@redhat.com>
* expmed.c (struct init_expmed_rtl): Split ...
(init_expmed_one_mode): ... out of ...
(init_expmed): ... here. Initialize integer vector modes also.
(synth_mult): Handle integer vector modes.
(choose_mult_variant): Likewise.
(expand_mult_const): Likewise.
(expand_mult): Likewise.
* machmode.h (GET_MODE_UNIT_BITSIZE): New.
2012-06-19 Richard Henderson <rth@redhat.com>
* config/i386/i386.c (ix86_rtx_costs): Handle CONST_VECTOR, and
* config/i386/i386.c (ix86_rtx_costs): Handle CONST_VECTOR, and
integral vector modes.
integral vector modes.
...
...
gcc/expmed.c
View file @
84ddb681
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
and shifts, multiplies and divides to rtl instructions.
and shifts, multiplies and divides to rtl instructions.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011
2011
, 2012
Free Software Foundation, Inc.
Free Software Foundation, Inc.
This file is part of GCC.
This file is part of GCC.
...
@@ -93,43 +93,112 @@ static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
...
@@ -93,43 +93,112 @@ static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
#define gen_extzv(a,b,c,d) NULL_RTX
#define gen_extzv(a,b,c,d) NULL_RTX
#endif
#endif
void
struct
init_expmed_rtl
init_expmed
(
void
)
{
{
struct
struct
rtx_def
reg
;
rtunion
reg_fld
[
2
];
{
struct
rtx_def
plus
;
rtunion
plus_fld1
;
struct
rtx_def
reg
;
rtunion
reg_fld
[
2
];
struct
rtx_def
neg
;
struct
rtx_def
plus
;
rtunion
plus_fld1
;
struct
rtx_def
mult
;
rtunion
mult_fld1
;
struct
rtx_def
neg
;
struct
rtx_def
sdiv
;
rtunion
sdiv_fld1
;
struct
rtx_def
mult
;
rtunion
mult_fld1
;
struct
rtx_def
udiv
;
rtunion
udiv_fld1
;
struct
rtx_def
sdiv
;
rtunion
sdiv_fld1
;
struct
rtx_def
zext
;
struct
rtx_def
udiv
;
rtunion
udiv_fld1
;
struct
rtx_def
sdiv_32
;
rtunion
sdiv_32_fld1
;
struct
rtx_def
zext
;
struct
rtx_def
smod_32
;
rtunion
smod_32_fld1
;
struct
rtx_def
sdiv_32
;
rtunion
sdiv_32_fld1
;
struct
rtx_def
wide_mult
;
rtunion
wide_mult_fld1
;
struct
rtx_def
smod_32
;
rtunion
smod_32_fld1
;
struct
rtx_def
wide_lshr
;
rtunion
wide_lshr_fld1
;
struct
rtx_def
wide_mult
;
rtunion
wide_mult_fld1
;
struct
rtx_def
wide_trunc
;
struct
rtx_def
wide_lshr
;
rtunion
wide_lshr_fld1
;
struct
rtx_def
shift
;
rtunion
shift_fld1
;
struct
rtx_def
wide_trunc
;
struct
rtx_def
shift_mult
;
rtunion
shift_mult_fld1
;
struct
rtx_def
shift
;
rtunion
shift_fld1
;
struct
rtx_def
shift_add
;
rtunion
shift_add_fld1
;
struct
rtx_def
shift_mult
;
rtunion
shift_mult_fld1
;
struct
rtx_def
shift_sub0
;
rtunion
shift_sub0_fld1
;
struct
rtx_def
shift_add
;
rtunion
shift_add_fld1
;
struct
rtx_def
shift_sub1
;
rtunion
shift_sub1_fld1
;
struct
rtx_def
shift_sub0
;
rtunion
shift_sub0_fld1
;
struct
rtx_def
shift_sub1
;
rtunion
shift_sub1_fld1
;
}
all
;
rtx
pow2
[
MAX_BITS_PER_WORD
];
rtx
pow2
[
MAX_BITS_PER_WORD
];
rtx
cint
[
MAX_BITS_PER_WORD
];
rtx
cint
[
MAX_BITS_PER_WORD
];
int
m
,
n
;
};
enum
machine_mode
mode
,
wider_mode
;
int
speed
;
static
void
init_expmed_one_mode
(
struct
init_expmed_rtl
*
all
,
enum
machine_mode
mode
,
int
speed
)
{
int
m
,
n
,
mode_bitsize
;
mode_bitsize
=
GET_MODE_UNIT_BITSIZE
(
mode
);
PUT_MODE
(
&
all
->
reg
,
mode
);
PUT_MODE
(
&
all
->
plus
,
mode
);
PUT_MODE
(
&
all
->
neg
,
mode
);
PUT_MODE
(
&
all
->
mult
,
mode
);
PUT_MODE
(
&
all
->
sdiv
,
mode
);
PUT_MODE
(
&
all
->
udiv
,
mode
);
PUT_MODE
(
&
all
->
sdiv_32
,
mode
);
PUT_MODE
(
&
all
->
smod_32
,
mode
);
PUT_MODE
(
&
all
->
wide_trunc
,
mode
);
PUT_MODE
(
&
all
->
shift
,
mode
);
PUT_MODE
(
&
all
->
shift_mult
,
mode
);
PUT_MODE
(
&
all
->
shift_add
,
mode
);
PUT_MODE
(
&
all
->
shift_sub0
,
mode
);
PUT_MODE
(
&
all
->
shift_sub1
,
mode
);
add_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
->
plus
,
speed
);
neg_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
->
neg
,
speed
);
mul_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
->
mult
,
speed
);
sdiv_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
->
sdiv
,
speed
);
udiv_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
->
udiv
,
speed
);
sdiv_pow2_cheap
[
speed
][
mode
]
=
(
set_src_cost
(
&
all
->
sdiv_32
,
speed
)
<=
2
*
add_cost
[
speed
][
mode
]);
smod_pow2_cheap
[
speed
][
mode
]
=
(
set_src_cost
(
&
all
->
smod_32
,
speed
)
<=
4
*
add_cost
[
speed
][
mode
]);
shift_cost
[
speed
][
mode
][
0
]
=
0
;
shiftadd_cost
[
speed
][
mode
][
0
]
=
shiftsub0_cost
[
speed
][
mode
][
0
]
=
shiftsub1_cost
[
speed
][
mode
][
0
]
=
add_cost
[
speed
][
mode
];
n
=
MIN
(
MAX_BITS_PER_WORD
,
mode_bitsize
);
for
(
m
=
1
;
m
<
n
;
m
++
)
{
XEXP
(
&
all
->
shift
,
1
)
=
all
->
cint
[
m
];
XEXP
(
&
all
->
shift_mult
,
1
)
=
all
->
pow2
[
m
];
shift_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
->
shift
,
speed
);
shiftadd_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
->
shift_add
,
speed
);
shiftsub0_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
->
shift_sub0
,
speed
);
shiftsub1_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
->
shift_sub1
,
speed
);
}
for
(
m
=
1
;
m
<
MAX_BITS_PER_WORD
;
m
++
)
if
(
SCALAR_INT_MODE_P
(
mode
)
)
{
{
pow2
[
m
]
=
GEN_INT
((
HOST_WIDE_INT
)
1
<<
m
);
enum
machine_mode
wider_mode
=
GET_MODE_WIDER_MODE
(
mode
);
cint
[
m
]
=
GEN_INT
(
m
);
if
(
wider_mode
!=
VOIDmode
)
{
PUT_MODE
(
&
all
->
zext
,
wider_mode
);
PUT_MODE
(
&
all
->
wide_mult
,
wider_mode
);
PUT_MODE
(
&
all
->
wide_lshr
,
wider_mode
);
XEXP
(
&
all
->
wide_lshr
,
1
)
=
GEN_INT
(
mode_bitsize
);
mul_widen_cost
[
speed
][
wider_mode
]
=
set_src_cost
(
&
all
->
wide_mult
,
speed
);
mul_highpart_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
->
wide_trunc
,
speed
);
}
}
}
}
void
init_expmed
(
void
)
{
struct
init_expmed_rtl
all
;
enum
machine_mode
mode
;
int
m
,
speed
;
memset
(
&
all
,
0
,
sizeof
all
);
memset
(
&
all
,
0
,
sizeof
all
);
for
(
m
=
1
;
m
<
MAX_BITS_PER_WORD
;
m
++
)
{
all
.
pow2
[
m
]
=
GEN_INT
((
HOST_WIDE_INT
)
1
<<
m
);
all
.
cint
[
m
]
=
GEN_INT
(
m
);
}
PUT_CODE
(
&
all
.
reg
,
REG
);
PUT_CODE
(
&
all
.
reg
,
REG
);
/* Avoid using hard regs in ways which may be unsupported. */
/* Avoid using hard regs in ways which may be unsupported. */
...
@@ -156,7 +225,7 @@ init_expmed (void)
...
@@ -156,7 +225,7 @@ init_expmed (void)
PUT_CODE
(
&
all
.
sdiv_32
,
DIV
);
PUT_CODE
(
&
all
.
sdiv_32
,
DIV
);
XEXP
(
&
all
.
sdiv_32
,
0
)
=
&
all
.
reg
;
XEXP
(
&
all
.
sdiv_32
,
0
)
=
&
all
.
reg
;
XEXP
(
&
all
.
sdiv_32
,
1
)
=
32
<
MAX_BITS_PER_WORD
?
cint
[
32
]
:
GEN_INT
(
32
);
XEXP
(
&
all
.
sdiv_32
,
1
)
=
32
<
MAX_BITS_PER_WORD
?
all
.
cint
[
32
]
:
GEN_INT
(
32
);
PUT_CODE
(
&
all
.
smod_32
,
MOD
);
PUT_CODE
(
&
all
.
smod_32
,
MOD
);
XEXP
(
&
all
.
smod_32
,
0
)
=
&
all
.
reg
;
XEXP
(
&
all
.
smod_32
,
0
)
=
&
all
.
reg
;
...
@@ -201,67 +270,14 @@ init_expmed (void)
...
@@ -201,67 +270,14 @@ init_expmed (void)
for
(
mode
=
GET_CLASS_NARROWEST_MODE
(
MODE_INT
);
for
(
mode
=
GET_CLASS_NARROWEST_MODE
(
MODE_INT
);
mode
!=
VOIDmode
;
mode
!=
VOIDmode
;
mode
=
GET_MODE_WIDER_MODE
(
mode
))
mode
=
GET_MODE_WIDER_MODE
(
mode
))
{
init_expmed_one_mode
(
&
all
,
mode
,
speed
);
PUT_MODE
(
&
all
.
reg
,
mode
);
PUT_MODE
(
&
all
.
plus
,
mode
);
PUT_MODE
(
&
all
.
neg
,
mode
);
PUT_MODE
(
&
all
.
mult
,
mode
);
PUT_MODE
(
&
all
.
sdiv
,
mode
);
PUT_MODE
(
&
all
.
udiv
,
mode
);
PUT_MODE
(
&
all
.
sdiv_32
,
mode
);
PUT_MODE
(
&
all
.
smod_32
,
mode
);
PUT_MODE
(
&
all
.
wide_trunc
,
mode
);
PUT_MODE
(
&
all
.
shift
,
mode
);
PUT_MODE
(
&
all
.
shift_mult
,
mode
);
PUT_MODE
(
&
all
.
shift_add
,
mode
);
PUT_MODE
(
&
all
.
shift_sub0
,
mode
);
PUT_MODE
(
&
all
.
shift_sub1
,
mode
);
add_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
.
plus
,
speed
);
neg_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
.
neg
,
speed
);
mul_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
.
mult
,
speed
);
sdiv_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
.
sdiv
,
speed
);
udiv_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
.
udiv
,
speed
);
sdiv_pow2_cheap
[
speed
][
mode
]
=
(
set_src_cost
(
&
all
.
sdiv_32
,
speed
)
<=
2
*
add_cost
[
speed
][
mode
]);
smod_pow2_cheap
[
speed
][
mode
]
=
(
set_src_cost
(
&
all
.
smod_32
,
speed
)
<=
4
*
add_cost
[
speed
][
mode
]);
wider_mode
=
GET_MODE_WIDER_MODE
(
mode
);
if
(
wider_mode
!=
VOIDmode
)
{
PUT_MODE
(
&
all
.
zext
,
wider_mode
);
PUT_MODE
(
&
all
.
wide_mult
,
wider_mode
);
PUT_MODE
(
&
all
.
wide_lshr
,
wider_mode
);
XEXP
(
&
all
.
wide_lshr
,
1
)
=
GEN_INT
(
GET_MODE_BITSIZE
(
mode
));
mul_widen_cost
[
speed
][
wider_mode
]
=
set_src_cost
(
&
all
.
wide_mult
,
speed
);
mul_highpart_cost
[
speed
][
mode
]
=
set_src_cost
(
&
all
.
wide_trunc
,
speed
);
}
shift_cost
[
speed
][
mode
][
0
]
=
0
;
shiftadd_cost
[
speed
][
mode
][
0
]
=
shiftsub0_cost
[
speed
][
mode
][
0
]
=
shiftsub1_cost
[
speed
][
mode
][
0
]
=
add_cost
[
speed
][
mode
];
n
=
MIN
(
MAX_BITS_PER_WORD
,
GET_MODE_BITSIZE
(
mode
));
for
(
mode
=
GET_CLASS_NARROWEST_MODE
(
MODE_VECTOR_INT
);
for
(
m
=
1
;
m
<
n
;
m
++
)
mode
!=
VOIDmode
;
{
mode
=
GET_MODE_WIDER_MODE
(
mode
))
XEXP
(
&
all
.
shift
,
1
)
=
cint
[
m
];
init_expmed_one_mode
(
&
all
,
mode
,
speed
);
XEXP
(
&
all
.
shift_mult
,
1
)
=
pow2
[
m
];
shift_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
.
shift
,
speed
);
shiftadd_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
.
shift_add
,
speed
);
shiftsub0_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
.
shift_sub0
,
speed
);
shiftsub1_cost
[
speed
][
mode
][
m
]
=
set_src_cost
(
&
all
.
shift_sub1
,
speed
);
}
}
}
}
if
(
alg_hash_used_p
)
if
(
alg_hash_used_p
)
memset
(
alg_hash
,
0
,
sizeof
(
alg_hash
));
memset
(
alg_hash
,
0
,
sizeof
(
alg_hash
));
else
else
...
@@ -2385,11 +2401,11 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
...
@@ -2385,11 +2401,11 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
int
op_cost
,
op_latency
;
int
op_cost
,
op_latency
;
unsigned
HOST_WIDE_INT
orig_t
=
t
;
unsigned
HOST_WIDE_INT
orig_t
=
t
;
unsigned
HOST_WIDE_INT
q
;
unsigned
HOST_WIDE_INT
q
;
int
maxm
=
MIN
(
BITS_PER_WORD
,
GET_MODE_BITSIZE
(
mode
));
int
maxm
,
hash_index
;
int
hash_index
;
bool
cache_hit
=
false
;
bool
cache_hit
=
false
;
enum
alg_code
cache_alg
=
alg_zero
;
enum
alg_code
cache_alg
=
alg_zero
;
bool
speed
=
optimize_insn_for_speed_p
();
bool
speed
=
optimize_insn_for_speed_p
();
enum
machine_mode
imode
;
/* Indicate that no algorithm is yet found. If no algorithm
/* Indicate that no algorithm is yet found. If no algorithm
is found, this value will be returned and indicate failure. */
is found, this value will be returned and indicate failure. */
...
@@ -2400,8 +2416,15 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
...
@@ -2400,8 +2416,15 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
||
(
cost_limit
->
cost
==
0
&&
cost_limit
->
latency
<=
0
))
||
(
cost_limit
->
cost
==
0
&&
cost_limit
->
latency
<=
0
))
return
;
return
;
/* Be prepared for vector modes. */
imode
=
GET_MODE_INNER
(
mode
);
if
(
imode
==
VOIDmode
)
imode
=
mode
;
maxm
=
MIN
(
BITS_PER_WORD
,
GET_MODE_BITSIZE
(
imode
));
/* Restrict the bits of "t" to the multiplication's mode. */
/* Restrict the bits of "t" to the multiplication's mode. */
t
&=
GET_MODE_MASK
(
mode
);
t
&=
GET_MODE_MASK
(
i
mode
);
/* t == 1 can be done in zero cost. */
/* t == 1 can be done in zero cost. */
if
(
t
==
1
)
if
(
t
==
1
)
...
@@ -2632,7 +2655,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
...
@@ -2632,7 +2655,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
op_cost
=
shiftsub1_cost
[
speed
][
mode
][
m
];
op_cost
=
shiftsub1_cost
[
speed
][
mode
][
m
];
new_limit
.
cost
=
best_cost
.
cost
-
op_cost
;
new_limit
.
cost
=
best_cost
.
cost
-
op_cost
;
new_limit
.
latency
=
best_cost
.
latency
-
op_cost
;
new_limit
.
latency
=
best_cost
.
latency
-
op_cost
;
synth_mult
(
alg_in
,
(
unsigned
HOST_WIDE_INT
)
(
-
orig_t
+
1
)
>>
m
,
&
new_limit
,
mode
);
synth_mult
(
alg_in
,
(
unsigned
HOST_WIDE_INT
)
(
-
orig_t
+
1
)
>>
m
,
&
new_limit
,
mode
);
alg_in
->
cost
.
cost
+=
op_cost
;
alg_in
->
cost
.
cost
+=
op_cost
;
alg_in
->
cost
.
latency
+=
op_cost
;
alg_in
->
cost
.
latency
+=
op_cost
;
...
@@ -2871,7 +2895,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
...
@@ -2871,7 +2895,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
/* Ensure that mult_cost provides a reasonable upper bound.
/* Ensure that mult_cost provides a reasonable upper bound.
Any constant multiplication can be performed with less
Any constant multiplication can be performed with less
than 2 * bits additions. */
than 2 * bits additions. */
op_cost
=
2
*
GET_MODE_BITSIZE
(
mode
)
*
add_cost
[
speed
][
mode
];
op_cost
=
2
*
GET_MODE_
UNIT_
BITSIZE
(
mode
)
*
add_cost
[
speed
][
mode
];
if
(
mult_cost
>
op_cost
)
if
(
mult_cost
>
op_cost
)
mult_cost
=
op_cost
;
mult_cost
=
op_cost
;
...
@@ -2882,7 +2906,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
...
@@ -2882,7 +2906,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
/* This works only if the inverted value actually fits in an
/* This works only if the inverted value actually fits in an
`unsigned int' */
`unsigned int' */
if
(
HOST_BITS_PER_INT
>=
GET_MODE_BITSIZE
(
mode
))
if
(
HOST_BITS_PER_INT
>=
GET_MODE_
UNIT_
BITSIZE
(
mode
))
{
{
op_cost
=
neg_cost
[
speed
][
mode
];
op_cost
=
neg_cost
[
speed
][
mode
];
if
(
MULT_COST_LESS
(
&
alg
->
cost
,
mult_cost
))
if
(
MULT_COST_LESS
(
&
alg
->
cost
,
mult_cost
))
...
@@ -2949,7 +2973,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
...
@@ -2949,7 +2973,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
if
(
alg
->
op
[
0
]
==
alg_zero
)
if
(
alg
->
op
[
0
]
==
alg_zero
)
{
{
accum
=
copy_to_mode_reg
(
mode
,
const0_rtx
);
accum
=
copy_to_mode_reg
(
mode
,
CONST0_RTX
(
mode
)
);
val_so_far
=
0
;
val_so_far
=
0
;
}
}
else
if
(
alg
->
op
[
0
]
==
alg_m
)
else
if
(
alg
->
op
[
0
]
==
alg_m
)
...
@@ -3029,24 +3053,25 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
...
@@ -3029,24 +3053,25 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
gcc_unreachable
();
gcc_unreachable
();
}
}
/* Write a REG_EQUAL note on the last insn so that we can cse
if
(
SCALAR_INT_MODE_P
(
mode
))
multiplication sequences. Note that if ACCUM is a SUBREG,
we've set the inner register and must properly indicate
that. */
tem
=
op0
,
nmode
=
mode
;
accum_inner
=
accum
;
if
(
GET_CODE
(
accum
)
==
SUBREG
)
{
{
accum_inner
=
SUBREG_REG
(
accum
);
/* Write a REG_EQUAL note on the last insn so that we can cse
nmode
=
GET_MODE
(
accum_inner
);
multiplication sequences. Note that if ACCUM is a SUBREG,
tem
=
gen_lowpart
(
nmode
,
op0
);
we've set the inner register and must properly indicate that. */
}
tem
=
op0
,
nmode
=
mode
;
accum_inner
=
accum
;
if
(
GET_CODE
(
accum
)
==
SUBREG
)
{
accum_inner
=
SUBREG_REG
(
accum
);
nmode
=
GET_MODE
(
accum_inner
);
tem
=
gen_lowpart
(
nmode
,
op0
);
}
insn
=
get_last_insn
();
insn
=
get_last_insn
();
set_dst_reg_note
(
insn
,
REG_EQUAL
,
set_dst_reg_note
(
insn
,
REG_EQUAL
,
gen_rtx_MULT
(
nmode
,
tem
,
GEN_INT
(
val_so_far
)),
gen_rtx_MULT
(
nmode
,
tem
,
GEN_INT
(
val_so_far
)),
accum_inner
);
accum_inner
);
}
}
}
if
(
variant
==
negate_variant
)
if
(
variant
==
negate_variant
)
...
@@ -3062,8 +3087,11 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
...
@@ -3062,8 +3087,11 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
/* Compare only the bits of val and val_so_far that are significant
/* Compare only the bits of val and val_so_far that are significant
in the result mode, to avoid sign-/zero-extension confusion. */
in the result mode, to avoid sign-/zero-extension confusion. */
val
&=
GET_MODE_MASK
(
mode
);
nmode
=
GET_MODE_INNER
(
mode
);
val_so_far
&=
GET_MODE_MASK
(
mode
);
if
(
nmode
==
VOIDmode
)
nmode
=
mode
;
val
&=
GET_MODE_MASK
(
nmode
);
val_so_far
&=
GET_MODE_MASK
(
nmode
);
gcc_assert
(
val
==
val_so_far
);
gcc_assert
(
val
==
val_so_far
);
return
accum
;
return
accum
;
...
@@ -3083,29 +3111,51 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
...
@@ -3083,29 +3111,51 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
{
{
enum
mult_variant
variant
;
enum
mult_variant
variant
;
struct
algorithm
algorithm
;
struct
algorithm
algorithm
;
rtx
scalar_op1
;
int
max_cost
;
int
max_cost
;
bool
speed
=
optimize_insn_for_speed_p
();
bool
speed
=
optimize_insn_for_speed_p
();
bool
do_trapv
=
flag_trapv
&&
SCALAR_INT_MODE_P
(
mode
)
&&
!
unsignedp
;
/* Handling const0_rtx here allows us to use zero as a rogue value for
if
(
CONSTANT_P
(
op0
))
coeff below. */
if
(
op1
==
const0_rtx
)
return
const0_rtx
;
if
(
op1
==
const1_rtx
)
return
op0
;
if
(
op1
==
constm1_rtx
)
return
expand_unop
(
mode
,
GET_MODE_CLASS
(
mode
)
==
MODE_INT
&&
!
unsignedp
&&
flag_trapv
?
negv_optab
:
neg_optab
,
op0
,
target
,
0
);
/* These are the operations that are potentially turned into a sequence
of shifts and additions. */
if
(
SCALAR_INT_MODE_P
(
mode
)
&&
(
unsignedp
||
!
flag_trapv
))
{
{
HOST_WIDE_INT
coeff
=
0
;
rtx
temp
=
op0
;
rtx
fake_reg
=
gen_raw_REG
(
mode
,
LAST_VIRTUAL_REGISTER
+
1
);
op0
=
op1
;
op1
=
temp
;
}
/* For vectors, there are several simplifications that can be made if
all elements of the vector constant are identical. */
scalar_op1
=
op1
;
if
(
GET_CODE
(
op1
)
==
CONST_VECTOR
)
{
int
i
,
n
=
CONST_VECTOR_NUNITS
(
op1
);
scalar_op1
=
CONST_VECTOR_ELT
(
op1
,
0
);
for
(
i
=
1
;
i
<
n
;
++
i
)
if
(
!
rtx_equal_p
(
scalar_op1
,
CONST_VECTOR_ELT
(
op1
,
i
)))
goto
skip_scalar
;
}
if
(
INTEGRAL_MODE_P
(
mode
))
{
rtx
fake_reg
;
HOST_WIDE_INT
coeff
;
bool
is_neg
;
int
mode_bitsize
;
if
(
op1
==
CONST0_RTX
(
mode
))
return
op1
;
if
(
op1
==
CONST1_RTX
(
mode
))
return
op0
;
if
(
op1
==
CONSTM1_RTX
(
mode
))
return
expand_unop
(
mode
,
do_trapv
?
negv_optab
:
neg_optab
,
op0
,
target
,
0
);
if
(
do_trapv
)
goto
skip_synth
;
/* These are the operations that are potentially turned into
a sequence of shifts and additions. */
mode_bitsize
=
GET_MODE_UNIT_BITSIZE
(
mode
);
/* synth_mult does an `unsigned int' multiply. As long as the mode is
/* synth_mult does an `unsigned int' multiply. As long as the mode is
less than or equal in size to `unsigned int' this doesn't matter.
less than or equal in size to `unsigned int' this doesn't matter.
...
@@ -3114,86 +3164,86 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
...
@@ -3114,86 +3164,86 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
any truncation. This means that multiplying by negative values does
any truncation. This means that multiplying by negative values does
not work; results are off by 2^32 on a 32 bit machine. */
not work; results are off by 2^32 on a 32 bit machine. */
if
(
CONST_INT_P
(
op1
))
if
(
CONST_INT_P
(
scalar_
op1
))
{
{
/* Attempt to handle multiplication of DImode values by negative
coeff
=
INTVAL
(
scalar_op1
);
coefficients, by performing the multiplication by a positive
is_neg
=
coeff
<
0
;
multiplier and then inverting the result. */
if
(
INTVAL
(
op1
)
<
0
&&
GET_MODE_BITSIZE
(
mode
)
>
HOST_BITS_PER_WIDE_INT
)
{
/* Its safe to use -INTVAL (op1) even for INT_MIN, as the
result is interpreted as an unsigned coefficient.
Exclude cost of op0 from max_cost to match the cost
calculation of the synth_mult. */
max_cost
=
(
set_src_cost
(
gen_rtx_MULT
(
mode
,
fake_reg
,
op1
),
speed
)
-
neg_cost
[
speed
][
mode
]);
if
(
max_cost
>
0
&&
choose_mult_variant
(
mode
,
-
INTVAL
(
op1
),
&
algorithm
,
&
variant
,
max_cost
))
{
rtx
temp
=
expand_mult_const
(
mode
,
op0
,
-
INTVAL
(
op1
),
NULL_RTX
,
&
algorithm
,
variant
);
return
expand_unop
(
mode
,
neg_optab
,
temp
,
target
,
0
);
}
}
else
coeff
=
INTVAL
(
op1
);
}
}
else
if
(
GET_CODE
(
op1
)
==
CONST_DOUBLE
)
else
if
(
CONST_DOUBLE_P
(
scalar_op1
)
)
{
{
/* If we are multiplying in DImode, it may still be a win
/* If we are multiplying in DImode, it may still be a win
to try to work with shifts and adds. */
to try to work with shifts and adds. */
if
(
CONST_DOUBLE_HIGH
(
op1
)
==
0
if
(
CONST_DOUBLE_HIGH
(
scalar_op1
)
==
0
&&
CONST_DOUBLE_LOW
(
op1
)
>
0
)
&&
CONST_DOUBLE_LOW
(
scalar_op1
)
>
0
)
coeff
=
CONST_DOUBLE_LOW
(
op1
);
else
if
(
CONST_DOUBLE_LOW
(
op1
)
==
0
&&
EXACT_POWER_OF_2_OR_ZERO_P
(
CONST_DOUBLE_HIGH
(
op1
)))
{
{
int
shift
=
floor_log2
(
CONST_DOUBLE_HIGH
(
op1
))
coeff
=
CONST_DOUBLE_LOW
(
scalar_op1
);
+
HOST_BITS_PER_WIDE_INT
;
is_neg
=
false
;
if
(
shift
<
HOST_BITS_PER_DOUBLE_INT
-
1
}
||
GET_MODE_BITSIZE
(
mode
)
<=
HOST_BITS_PER_DOUBLE_INT
)
else
if
(
CONST_DOUBLE_LOW
(
scalar_op1
)
==
0
)
return
expand_shift
(
LSHIFT_EXPR
,
mode
,
op0
,
{
shift
,
target
,
unsignedp
);
coeff
=
CONST_DOUBLE_HIGH
(
scalar_op1
);
if
(
EXACT_POWER_OF_2_OR_ZERO_P
(
coeff
))
{
int
shift
=
floor_log2
(
coeff
)
+
HOST_BITS_PER_WIDE_INT
;
if
(
shift
<
HOST_BITS_PER_DOUBLE_INT
-
1
||
mode_bitsize
<=
HOST_BITS_PER_DOUBLE_INT
)
return
expand_shift
(
LSHIFT_EXPR
,
mode
,
op0
,
shift
,
target
,
unsignedp
);
}
goto
skip_synth
;
}
}
}
}
else
goto
skip_synth
;
/* We used to test optimize here, on the grounds that it's better to
/* We used to test optimize here, on the grounds that it's better to
produce a smaller program when -O is not used. But this causes
produce a smaller program when -O is not used. But this causes
such a terrible slowdown sometimes that it seems better to always
such a terrible slowdown sometimes that it seems better to always
use synth_mult. */
use synth_mult. */
if
(
coeff
!=
0
)
{
/* Special case powers of two. */
if
(
EXACT_POWER_OF_2_OR_ZERO_P
(
coeff
))
return
expand_shift
(
LSHIFT_EXPR
,
mode
,
op0
,
floor_log2
(
coeff
),
target
,
unsignedp
);
/* Exclude cost of op0 from max_cost to match the cost
/* Special case powers of two. */
if
(
EXACT_POWER_OF_2_OR_ZERO_P
(
coeff
))
return
expand_shift
(
LSHIFT_EXPR
,
mode
,
op0
,
floor_log2
(
coeff
),
target
,
unsignedp
);
fake_reg
=
gen_raw_REG
(
mode
,
LAST_VIRTUAL_REGISTER
+
1
);
/* Attempt to handle multiplication of DImode values by negative
coefficients, by performing the multiplication by a positive
multiplier and then inverting the result. */
/* ??? How is this not slightly redundant with the neg variant? */
if
(
is_neg
&&
mode_bitsize
>
HOST_BITS_PER_WIDE_INT
)
{
/* Its safe to use -coeff even for INT_MIN, as the
result is interpreted as an unsigned coefficient.
Exclude cost of op0 from max_cost to match the cost
calculation of the synth_mult. */
calculation of the synth_mult. */
max_cost
=
set_src_cost
(
gen_rtx_MULT
(
mode
,
fake_reg
,
op1
),
speed
);
max_cost
=
(
set_src_cost
(
gen_rtx_MULT
(
mode
,
fake_reg
,
op1
),
speed
)
if
(
choose_mult_variant
(
mode
,
coeff
,
&
algorithm
,
&
variant
,
-
neg_cost
[
speed
][
mode
]);
max_cost
))
if
(
max_cost
>
0
return
expand_mult_const
(
mode
,
op0
,
coeff
,
target
,
&&
choose_mult_variant
(
mode
,
-
coeff
,
&
algorithm
,
&
algorithm
,
variant
);
&
variant
,
max_cost
))
{
rtx
temp
=
expand_mult_const
(
mode
,
op0
,
-
coeff
,
NULL_RTX
,
&
algorithm
,
variant
);
return
expand_unop
(
mode
,
neg_optab
,
temp
,
target
,
0
);
}
}
}
}
if
(
GET_CODE
(
op0
)
==
CONST_DOUBLE
)
/* Exclude cost of op0 from max_cost to match the cost
{
calculation of the synth_mult. */
rtx
temp
=
op0
;
max_cost
=
set_src_cost
(
gen_rtx_MULT
(
mode
,
fake_reg
,
op1
),
speed
);
op0
=
op1
;
if
(
choose_mult_variant
(
mode
,
coeff
,
&
algorithm
,
&
variant
,
max_cost
))
op1
=
temp
;
return
expand_mult_const
(
mode
,
op0
,
coeff
,
target
,
&
algorithm
,
variant
);
}
}
skip_synth
:
/* Expand x*2.0 as x+x. */
/* Expand x*2.0 as x+x. */
if
(
GET_CODE
(
op1
)
==
CONST_DOUBLE
if
(
GET_CODE
(
scalar_op1
)
==
CONST_DOUBLE
&&
FLOAT_MODE_P
(
mode
))
&&
SCALAR_FLOAT_MODE_P
(
mode
))
{
{
REAL_VALUE_TYPE
d
;
REAL_VALUE_TYPE
d
;
REAL_VALUE_FROM_CONST_DOUBLE
(
d
,
op1
);
REAL_VALUE_FROM_CONST_DOUBLE
(
d
,
scalar_
op1
);
if
(
REAL_VALUES_EQUAL
(
d
,
dconst2
))
if
(
REAL_VALUES_EQUAL
(
d
,
dconst2
))
{
{
...
@@ -3202,13 +3252,11 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
...
@@ -3202,13 +3252,11 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
target
,
unsignedp
,
OPTAB_LIB_WIDEN
);
target
,
unsignedp
,
OPTAB_LIB_WIDEN
);
}
}
}
}
skip_scalar
:
/* This used to use umul_optab if unsigned, but for non-widening multiply
/* This used to use umul_optab if unsigned, but for non-widening multiply
there is no difference between signed and unsigned. */
there is no difference between signed and unsigned. */
op0
=
expand_binop
(
mode
,
op0
=
expand_binop
(
mode
,
do_trapv
?
smulv_optab
:
smul_optab
,
!
unsignedp
&&
flag_trapv
&&
(
GET_MODE_CLASS
(
mode
)
==
MODE_INT
)
?
smulv_optab
:
smul_optab
,
op0
,
op1
,
target
,
unsignedp
,
OPTAB_LIB_WIDEN
);
op0
,
op1
,
target
,
unsignedp
,
OPTAB_LIB_WIDEN
);
gcc_assert
(
op0
);
gcc_assert
(
op0
);
return
op0
;
return
op0
;
...
...
gcc/machmode.h
View file @
84ddb681
/* Machine mode definitions for GCC; included by rtl.h and tree.h.
/* Machine mode definitions for GCC; included by rtl.h and tree.h.
Copyright (C) 1991, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2003,
Copyright (C) 1991, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2003,
2007, 2008, 2009, 2010 Free Software Foundation, Inc.
2007, 2008, 2009, 2010
, 2012
Free Software Foundation, Inc.
This file is part of GCC.
This file is part of GCC.
...
@@ -179,7 +179,8 @@ extern const unsigned char mode_class[NUM_MACHINE_MODES];
...
@@ -179,7 +179,8 @@ extern const unsigned char mode_class[NUM_MACHINE_MODES];
extern
CONST_MODE_SIZE
unsigned
char
mode_size
[
NUM_MACHINE_MODES
];
extern
CONST_MODE_SIZE
unsigned
char
mode_size
[
NUM_MACHINE_MODES
];
#define GET_MODE_SIZE(MODE) ((unsigned short) mode_size[MODE])
#define GET_MODE_SIZE(MODE) ((unsigned short) mode_size[MODE])
#define GET_MODE_BITSIZE(MODE) ((unsigned short) (GET_MODE_SIZE (MODE) * BITS_PER_UNIT))
#define GET_MODE_BITSIZE(MODE) \
((unsigned short) (GET_MODE_SIZE (MODE) * BITS_PER_UNIT))
/* Get the number of value bits of an object of mode MODE. */
/* Get the number of value bits of an object of mode MODE. */
extern
const
unsigned
short
mode_precision
[
NUM_MACHINE_MODES
];
extern
const
unsigned
short
mode_precision
[
NUM_MACHINE_MODES
];
...
@@ -205,13 +206,17 @@ extern const unsigned HOST_WIDE_INT mode_mask_array[NUM_MACHINE_MODES];
...
@@ -205,13 +206,17 @@ extern const unsigned HOST_WIDE_INT mode_mask_array[NUM_MACHINE_MODES];
extern
const
unsigned
char
mode_inner
[
NUM_MACHINE_MODES
];
extern
const
unsigned
char
mode_inner
[
NUM_MACHINE_MODES
];
#define GET_MODE_INNER(MODE) ((enum machine_mode) mode_inner[MODE])
#define GET_MODE_INNER(MODE) ((enum machine_mode) mode_inner[MODE])
/* Get the size in bytes of the basic parts of an object of mode MODE. */
/* Get the size in bytes or bites of the basic parts of an
object of mode MODE. */
#define GET_MODE_UNIT_SIZE(MODE) \
#define GET_MODE_UNIT_SIZE(MODE) \
(GET_MODE_INNER (MODE) == VOIDmode \
(GET_MODE_INNER (MODE) == VOIDmode \
? GET_MODE_SIZE (MODE) \
? GET_MODE_SIZE (MODE) \
: GET_MODE_SIZE (GET_MODE_INNER (MODE)))
: GET_MODE_SIZE (GET_MODE_INNER (MODE)))
#define GET_MODE_UNIT_BITSIZE(MODE) \
((unsigned short) (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT))
/* Get the number of units in the object. */
/* Get the number of units in the object. */
extern
const
unsigned
char
mode_nunits
[
NUM_MACHINE_MODES
];
extern
const
unsigned
char
mode_nunits
[
NUM_MACHINE_MODES
];
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment