diff mbox

[1/2] Enable setting sign and unsigned promoted mode (SPR_SIGNED_AND_UNSIGNED)

Message ID 53AA7864.9020500@linaro.org
State New
Headers show

Commit Message

Kugan Vivekanandarajah June 25, 2014, 7:21 a.m. UTC
>> +const unsigned int SRP_POINTER  = -1;
>> +const unsigned int SRP_SIGNED   = 0;
>> +const unsigned int SRP_UNSIGNED = 1;
>> +const unsigned int SRP_SIGNED_AND_UNSIGNED = 2;
> 
> But most importantly, I thought Richard Henderson suggested
> to use SRP_POINTER 0, SRP_SIGNED 1, SRP_UNSIGNED 2, SRP_SIGNED_AND_UNSIGNED 3,
> that way when checking e.g. SUBREG_PROMOTED_SIGNED_P or
> SUBREG_PROMOTED_UNSIGNED_P you can check just the single bit.
> Where something tested for SUBREG_PROMOTED_UNSIGNED_P () == -1 just
> use SUBREG_PROMOTED_GET.

The problem with SRP_POINTER 0, SRP_SIGNED 1, SRP_UNSIGNED 2,
SRP_SIGNED_AND_UNSIGNED 3 (as I understand) is that, it will be
incompatible with TYPE_UNSIGNED (tree) and defines of
POINTER_EXTEND_UNSIGNED values. We will have to then translate while
setting to SRP_* values . Also SUBREG_PROMOTED_SIGNED_P is now checked
in some cases for != 0 (meaning SRP_POINTER or SRP_UNSIGNED) and in some
cases > 0 (meaning SRP_UNSIGNED).

Since our aim is to perform single bit checks, why don’t we just use
this representation internally (i.e.  _rtx->unchanging = 1 if SRP_SIGNED
and _rtx->volatil = 1 if SRP_UNSIGNED). As for SUBREG_PROMOTED_SIGNED_P,
we still have to return -1 or 1 depending on SRP_POINTER or SRP_UNSIGNED.


const unsigned int SRP_POINTER	= -1;
const unsigned int SRP_SIGNED   = 0;
const unsigned int SRP_UNSIGNED = 1;
const unsigned int SRP_SIGNED_AND_UNSIGNED = 2;

/* Sets promoted mode for SUBREG_PROMOTED_VAR_P(), */
#define SUBREG_PROMOTED_SET(RTX, VAL)	                        \
do {							        \
  rtx const _rtx = RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_SET",	\
                                    (RTX), SUBREG);		\
  switch ((VAL))						\
  {								\
    case SRP_POINTER:						\
      _rtx->volatil = 0;					\
      _rtx->unchanging = 0;					\
      break;							\
    case SRP_SIGNED:						\
      _rtx->volatil = 0;					\
      _rtx->unchanging = 1;					\
      break;							\
    case SRP_UNSIGNED:						\
      _rtx->volatil = 1;					\
      _rtx->unchanging = 0;					\
      break;							\
    case SRP_SIGNED_AND_UNSIGNED:				\
      _rtx->volatil = 1;					\
      _rtx->unchanging = 1;					\
      break;							\
  }								\
} while (0)

/* Gets promoted mode for SUBREG_PROMOTED_VAR_P(). */
#define SUBREG_PROMOTED_GET(RTX)	\
  (2 * (RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_GET", (RTX), SUBREG)->volatil)\
   + (RTX)->unchanging - 1)

/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
   for SIGNED type.  */
#define SUBREG_PROMOTED_SIGNED_P(RTX)	\
  (RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_SIGNED_P", (RTX),
SUBREG)->unchanging == 1)

/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
   for UNSIGNED type.  In case of SRP_POINTER, SUBREG_PROMOTED_UNSIGNED_P
   returns -1 as this is in most cases handled like unsigned extension,
   except for generating instructions where special code is emitted for
   (ptr_extend insns) on some architectures.  */
   #define SUBREG_PROMOTED_UNSIGNED_P(RTX)	\
  ((((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX),
SUBREG)->volatil)\
     + (RTX)->unchanging) == 0) ? -1 : ((RTX)->volatil == 1))

Am I missing anything here? Please let me know. I am attaching the patch
based on this with your other review comments addressed.

Thanks,
Kugan

gcc/
2014-06-25  Kugan Vivekanandarajah  <kuganv@linaro.org>

	* calls.c (precompute_arguments): Use new SUBREG_PROMOTED_SET
	instead of SUBREG_PROMOTED_UNSIGNED_SET
	(expand_call): Likewise.
	* expr.c (convert_move): Use new SUBREG_CHECK_PROMOTED_SIGN
	instead of SUBREG_PROMOTED_UNSIGNED_P.
	(convert_modes): Likewise.
	(store_expr): Likewise.
	(expand_expr_real_1): Use new SUBREG_PROMOTED_SET
	instead of SUBREG_PROMOTED_UNSIGNED_SET.
	* function.c (assign_param_setup_reg): Use new SUBREG_PROMOTED_SET
	instead of SUBREG_PROMOTED_UNSIGNED_SET.
	* ifcvt.c (noce_emit_cmove): Updated to use
	SUBREG_PROMOTED_UNSIGNED_P and SUBREG_PROMOTED_SIGNED_P.
	* internal-fn.c (ubsan_expand_si_overflow_mul_check): Use
	SUBREG_PROMOTED_SET instead of SUBREG_PROMOTED_UNSIGNED_SET.
	* optabs.c (widen_operand): Use new SUBREG_CHECK_PROMOTED_SIGN
	instead of SUBREG_PROMOTED_UNSIGNED_P.
	* rtl.h (SUBREG_PROMOTED_UNSIGNED_SET): Remove.
	(SUBREG_PROMOTED_SET): New define.
	(SUBREG_PROMOTED_GET): Likewise.
	(SUBREG_PROMOTED_SIGNED_P): Likewise.
	(SUBREG_CHECK_PROMOTED_SIGN): Likewise.
	(SUBREG_PROMOTED_UNSIGNED_P): Updated.
	* rtlanal.c (simplify_unary_operation_1): Use new
	SUBREG_PROMOTED_SET instead of SUBREG_PROMOTED_UNSIGNED_SET.
	* simplify-rtx.c (simplify_unary_operation_1): Use new
	SUBREG_PROMOTED_SIGNED_P instead of
	!SUBREG_PROMOTED_UNSIGNED_P.
	(simplify_subreg): Use new SUBREG_PROMOTED_SET instead of
	 SUBREG_PROMOTED_UNSIGNED_SET.

Comments

Jakub Jelinek June 25, 2014, 7:50 a.m. UTC | #1
On Wed, Jun 25, 2014 at 05:21:08PM +1000, Kugan wrote:
> The problem with SRP_POINTER 0, SRP_SIGNED 1, SRP_UNSIGNED 2,
> SRP_SIGNED_AND_UNSIGNED 3 (as I understand) is that, it will be
> incompatible with TYPE_UNSIGNED (tree) and defines of
> POINTER_EXTEND_UNSIGNED values. We will have to then translate while
> setting to SRP_* values . Also SUBREG_PROMOTED_SIGNED_P is now checked
> in some cases for != 0 (meaning SRP_POINTER or SRP_UNSIGNED) and in some
> cases > 0 (meaning SRP_UNSIGNED).
> 
> Since our aim is to perform single bit checks, why don’t we just use
> this representation internally (i.e.  _rtx->unchanging = 1 if SRP_SIGNED
> and _rtx->volatil = 1 if SRP_UNSIGNED). As for SUBREG_PROMOTED_SIGNED_P,
> we still have to return -1 or 1 depending on SRP_POINTER or SRP_UNSIGNED.

Why don't you make SUBREG_PROMOTED_UNSIGNED_P just return 0/1 (i.e. the
single bit), and for places where it would like to match both
SRP_UNSIGNED and SRP_POINTER use SUBREG_PROMOTED_GET () & SRP_UNSIGNED
or so?

> --- a/gcc/ifcvt.c
> +++ b/gcc/ifcvt.c
> @@ -1448,8 +1448,11 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
>  	  || byte_vtrue != byte_vfalse
>  	  || (SUBREG_PROMOTED_VAR_P (vtrue)
>  	      != SUBREG_PROMOTED_VAR_P (vfalse))
> -	  || (SUBREG_PROMOTED_UNSIGNED_P (vtrue)
> -	      != SUBREG_PROMOTED_UNSIGNED_P (vfalse)))
> +	  || ((SUBREG_PROMOTED_UNSIGNED_P (vtrue)
> +	       != SUBREG_PROMOTED_UNSIGNED_P (vfalse))
> +	      && (SUBREG_PROMOTED_SIGNED_P (vtrue)
> +		  != SUBREG_PROMOTED_SIGNED_P (vfalse))))

Shouldn't this be SUBREG_PROMOTED_GET (vtrue) != SUBREG_PROMOTED_GET (vfalse) ?

> +const unsigned int SRP_POINTER	= -1;
> +const unsigned int SRP_SIGNED   = 0;

Inconsistent whitespace, just use space instead of multiple spaces and/or
tabs.

> +const unsigned int SRP_UNSIGNED = 1;
> +const unsigned int SRP_SIGNED_AND_UNSIGNED = 2;

> +/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
> +   for SIGNED type.  */
> +#define SUBREG_PROMOTED_SIGNED_P(RTX)	\
> +  (RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_SIGNED_P", (RTX), SUBREG)->unchanging == 1)

Why the " == 1" ?
> +
> +/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
> +   for UNSIGNED type.  In case of SRP_POINTER, SUBREG_PROMOTED_UNSIGNED_P
> +   returns -1 as this is in most cases handled like unsigned extension,
> +   except for generating instructions where special code is emitted for
> +   (ptr_extend insns) on some architectures.  */
>  #define SUBREG_PROMOTED_UNSIGNED_P(RTX)	\
> -  ((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil) \
> -   ? -1 : (int) (RTX)->unchanging)
> +  ((((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil)\
> +     + (RTX)->unchanging) == 0) ? -1 : ((RTX)->volatil == 1))
> +
> +/* Checks if RTX of SUBREG_PROMOTED_VAR_P() is promotd for given SIGN.  */
> +#define	SUBREG_CHECK_PROMOTED_SIGN(RTX, SIGN) \

Use space rather than tab.  Also, why do we need this macro?
Can't you just use SUBREG_PROMOTED_GET () == sign ?  I mean, sign in that
case is typically just 0 or 1.

	Jakub
Kugan Vivekanandarajah June 26, 2014, 1:06 a.m. UTC | #2
On 25/06/14 17:50, Jakub Jelinek wrote:
> On Wed, Jun 25, 2014 at 05:21:08PM +1000, Kugan wrote:
>> The problem with SRP_POINTER 0, SRP_SIGNED 1, SRP_UNSIGNED 2,
>> SRP_SIGNED_AND_UNSIGNED 3 (as I understand) is that, it will be
>> incompatible with TYPE_UNSIGNED (tree) and defines of
>> POINTER_EXTEND_UNSIGNED values. We will have to then translate while
>> setting to SRP_* values . Also SUBREG_PROMOTED_SIGNED_P is now checked
>> in some cases for != 0 (meaning SRP_POINTER or SRP_UNSIGNED) and in some
>> cases > 0 (meaning SRP_UNSIGNED).
>>
>> Since our aim is to perform single bit checks, why don’t we just use
>> this representation internally (i.e.  _rtx->unchanging = 1 if SRP_SIGNED
>> and _rtx->volatil = 1 if SRP_UNSIGNED). As for SUBREG_PROMOTED_SIGNED_P,
>> we still have to return -1 or 1 depending on SRP_POINTER or SRP_UNSIGNED.
> 
> Why don't you make SUBREG_PROMOTED_UNSIGNED_P just return 0/1 (i.e. the
> single bit), and for places where it would like to match both
> SRP_UNSIGNED and SRP_POINTER use SUBREG_PROMOTED_GET () & SRP_UNSIGNED
> or so?

If we use SUBREG_PROMOTED_GET () & SRP_UNSIGNED, we will miss
the case SRP_SIGNED_AND_UNSIGNED. Though this is not wrong, we might
miss some optimization opportunities here. We can however use
(SUBREG_PROMOTED_GET () != SRP_SIGNED) if you like this. Other option is
to define another macro that explicilty says some think like
SUBREG_PROMOTED_POINTER_OR_UNSIGNED_P.

>> --- a/gcc/ifcvt.c
>> +++ b/gcc/ifcvt.c
>> @@ -1448,8 +1448,11 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
>>  	  || byte_vtrue != byte_vfalse
>>  	  || (SUBREG_PROMOTED_VAR_P (vtrue)
>>  	      != SUBREG_PROMOTED_VAR_P (vfalse))
>> -	  || (SUBREG_PROMOTED_UNSIGNED_P (vtrue)
>> -	      != SUBREG_PROMOTED_UNSIGNED_P (vfalse)))
>> +	  || ((SUBREG_PROMOTED_UNSIGNED_P (vtrue)
>> +	       != SUBREG_PROMOTED_UNSIGNED_P (vfalse))
>> +	      && (SUBREG_PROMOTED_SIGNED_P (vtrue)
>> +		  != SUBREG_PROMOTED_SIGNED_P (vfalse))))
> 
> Shouldn't this be SUBREG_PROMOTED_GET (vtrue) != SUBREG_PROMOTED_GET (vfalse) ?

The reason why I checked like this to cover one side with
SRP_SIGNED_AND_UNSIGNED and other with  SRP_SIGNED or SRP_UNSIGNED. If
we check SUBREG_PROMOTED_GET (vtrue) != SUBREG_PROMOTED_GET (vfalse) we
will miss that.

>> +
>> +/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
>> +   for UNSIGNED type.  In case of SRP_POINTER, SUBREG_PROMOTED_UNSIGNED_P
>> +   returns -1 as this is in most cases handled like unsigned extension,
>> +   except for generating instructions where special code is emitted for
>> +   (ptr_extend insns) on some architectures.  */
>>  #define SUBREG_PROMOTED_UNSIGNED_P(RTX)	\
>> -  ((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil) \
>> -   ? -1 : (int) (RTX)->unchanging)
>> +  ((((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil)\
>> +     + (RTX)->unchanging) == 0) ? -1 : ((RTX)->volatil == 1))
>> +
>> +/* Checks if RTX of SUBREG_PROMOTED_VAR_P() is promotd for given SIGN.  */
>> +#define	SUBREG_CHECK_PROMOTED_SIGN(RTX, SIGN) \
> 
> Use space rather than tab.  Also, why do we need this macro?
> Can't you just use SUBREG_PROMOTED_GET () == sign ?  I mean, sign in that
> case is typically just 0 or 1.

Again I wanted to cover SRP_SIGNED_AND_UNSIGNED as well in this case.


Thanks,
Kugan
Jakub Jelinek June 26, 2014, 5:50 a.m. UTC | #3
On Thu, Jun 26, 2014 at 11:06:26AM +1000, Kugan wrote:
> >> Since our aim is to perform single bit checks, why don’t we just use
> >> this representation internally (i.e.  _rtx->unchanging = 1 if SRP_SIGNED
> >> and _rtx->volatil = 1 if SRP_UNSIGNED). As for SUBREG_PROMOTED_SIGNED_P,
> >> we still have to return -1 or 1 depending on SRP_POINTER or SRP_UNSIGNED.
> > 
> > Why don't you make SUBREG_PROMOTED_UNSIGNED_P just return 0/1 (i.e. the
> > single bit), and for places where it would like to match both
> > SRP_UNSIGNED and SRP_POINTER use SUBREG_PROMOTED_GET () & SRP_UNSIGNED
> > or so?
> 
> If we use SUBREG_PROMOTED_GET () & SRP_UNSIGNED, we will miss
> the case SRP_SIGNED_AND_UNSIGNED. Though this is not wrong, we might
> miss some optimization opportunities here. We can however use
> (SUBREG_PROMOTED_GET () != SRP_SIGNED) if you like this. Other option is
> to define another macro that explicilty says some think like
> SUBREG_PROMOTED_POINTER_OR_UNSIGNED_P.

Ok, sure, if you want to make the test pass for SRP_UNSIGNED, SRP_POINTER
and SRP_UNSIGNED_AND_SIGNED, then != SRP_SIGNED is the right thing.
What I wanted is make SUBREG_PROMOTED_UNSIGNED_P be a 0/1 again.

> >> --- a/gcc/ifcvt.c
> >> +++ b/gcc/ifcvt.c
> >> @@ -1448,8 +1448,11 @@ noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
> >>  	  || byte_vtrue != byte_vfalse
> >>  	  || (SUBREG_PROMOTED_VAR_P (vtrue)
> >>  	      != SUBREG_PROMOTED_VAR_P (vfalse))
> >> -	  || (SUBREG_PROMOTED_UNSIGNED_P (vtrue)
> >> -	      != SUBREG_PROMOTED_UNSIGNED_P (vfalse)))
> >> +	  || ((SUBREG_PROMOTED_UNSIGNED_P (vtrue)
> >> +	       != SUBREG_PROMOTED_UNSIGNED_P (vfalse))
> >> +	      && (SUBREG_PROMOTED_SIGNED_P (vtrue)
> >> +		  != SUBREG_PROMOTED_SIGNED_P (vfalse))))
> > 
> > Shouldn't this be SUBREG_PROMOTED_GET (vtrue) != SUBREG_PROMOTED_GET (vfalse) ?
> 
> The reason why I checked like this to cover one side with
> SRP_SIGNED_AND_UNSIGNED and other with  SRP_SIGNED or SRP_UNSIGNED. If
> we check SUBREG_PROMOTED_GET (vtrue) != SUBREG_PROMOTED_GET (vfalse) we
> will miss that.

What you have above is just wrong though.  Either you need to make sure the
flags are the same (i.e. GET != GET), and keep the SET a few lines below as
is, or you would allow (some?) mismatches of the promotion flags,
but in that case you'd need to deal with it in the SET conservatively.
Like, if one is SRP_SIGNED_AND_UNSIGNED and another one is just
SRP_SIGNED or just SRP_UNSIGNED, you'd use the simpler one, if one
is promoted and another one is not, you'd not make the SUBREG promoted at
all, etc.  Not worth it IMHO, at least not for now.

> 
> >> +
> >> +/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
> >> +   for UNSIGNED type.  In case of SRP_POINTER, SUBREG_PROMOTED_UNSIGNED_P
> >> +   returns -1 as this is in most cases handled like unsigned extension,
> >> +   except for generating instructions where special code is emitted for
> >> +   (ptr_extend insns) on some architectures.  */
> >>  #define SUBREG_PROMOTED_UNSIGNED_P(RTX)	\
> >> -  ((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil) \
> >> -   ? -1 : (int) (RTX)->unchanging)
> >> +  ((((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil)\
> >> +     + (RTX)->unchanging) == 0) ? -1 : ((RTX)->volatil == 1))
> >> +
> >> +/* Checks if RTX of SUBREG_PROMOTED_VAR_P() is promotd for given SIGN.  */
> >> +#define	SUBREG_CHECK_PROMOTED_SIGN(RTX, SIGN) \
> > 
> > Use space rather than tab.  Also, why do we need this macro?
> > Can't you just use SUBREG_PROMOTED_GET () == sign ?  I mean, sign in that
> > case is typically just 0 or 1.
> 
> Again I wanted to cover SRP_SIGNED_AND_UNSIGNED as well in this case.

Ah, ok.  It is fine as is (with the whitespace change).

	Jakub
diff mbox

Patch

diff --git a/gcc/calls.c b/gcc/calls.c
index 78fe7d8..a3e6faa 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1484,8 +1484,7 @@  precompute_arguments (int num_actuals, struct arg_data *args)
 	      args[i].initial_value
 		= gen_lowpart_SUBREG (mode, args[i].value);
 	      SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1;
-	      SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value,
-					    args[i].unsignedp);
+	      SUBREG_PROMOTED_SET (args[i].initial_value, args[i].unsignedp);
 	    }
 	}
     }
@@ -3365,7 +3364,7 @@  expand_call (tree exp, rtx target, int ignore)
 
 	  target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
 	  SUBREG_PROMOTED_VAR_P (target) = 1;
-	  SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp);
+	  SUBREG_PROMOTED_SET (target, unsignedp);
 	}
 
       /* If size of args is variable or this was a constructor call for a stack
diff --git a/gcc/expr.c b/gcc/expr.c
index 512c024..da02a06 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -329,7 +329,7 @@  convert_move (rtx to, rtx from, int unsignedp)
   if (GET_CODE (from) == SUBREG && SUBREG_PROMOTED_VAR_P (from)
       && (GET_MODE_PRECISION (GET_MODE (SUBREG_REG (from)))
 	  >= GET_MODE_PRECISION (to_mode))
-      && SUBREG_PROMOTED_UNSIGNED_P (from) == unsignedp)
+      && SUBREG_CHECK_PROMOTED_SIGN (from, unsignedp))
     from = gen_lowpart (to_mode, from), from_mode = to_mode;
 
   gcc_assert (GET_CODE (to) != SUBREG || !SUBREG_PROMOTED_VAR_P (to));
@@ -703,7 +703,7 @@  convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int uns
 
   if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
       && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) >= GET_MODE_SIZE (mode)
-      && SUBREG_PROMOTED_UNSIGNED_P (x) == unsignedp)
+      && SUBREG_CHECK_PROMOTED_SIGN (x, unsignedp))
     x = gen_lowpart (mode, SUBREG_REG (x));
 
   if (GET_MODE (x) != VOIDmode)
@@ -5202,8 +5202,8 @@  store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 	  && GET_MODE_PRECISION (GET_MODE (target))
 	     == TYPE_PRECISION (TREE_TYPE (exp)))
 	{
-	  if (TYPE_UNSIGNED (TREE_TYPE (exp))
-	      != SUBREG_PROMOTED_UNSIGNED_P (target))
+	  if (!SUBREG_CHECK_PROMOTED_SIGN (target,
+					   TYPE_UNSIGNED (TREE_TYPE (exp))))
 	    {
 	      /* Some types, e.g. Fortran's logical*4, won't have a signed
 		 version, so use the mode instead.  */
@@ -9513,7 +9513,7 @@  expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
 	  temp = gen_lowpart_SUBREG (mode, decl_rtl);
 	  SUBREG_PROMOTED_VAR_P (temp) = 1;
-	  SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
+	  SUBREG_PROMOTED_SET (temp, unsignedp);
 	  return temp;
 	}
 
diff --git a/gcc/function.c b/gcc/function.c
index 441289e..9509622 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -3093,7 +3093,7 @@  assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 	  /* The argument is already sign/zero extended, so note it
 	     into the subreg.  */
 	  SUBREG_PROMOTED_VAR_P (tempreg) = 1;
-	  SUBREG_PROMOTED_UNSIGNED_SET (tempreg, unsignedp);
+	  SUBREG_PROMOTED_SET (tempreg, unsignedp);
 	}
 
       /* TREE_USED gets set erroneously during expand_assignment.  */
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 816cdaa..b2a0574 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -1448,8 +1448,11 @@  noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
 	  || byte_vtrue != byte_vfalse
 	  || (SUBREG_PROMOTED_VAR_P (vtrue)
 	      != SUBREG_PROMOTED_VAR_P (vfalse))
-	  || (SUBREG_PROMOTED_UNSIGNED_P (vtrue)
-	      != SUBREG_PROMOTED_UNSIGNED_P (vfalse)))
+	  || ((SUBREG_PROMOTED_UNSIGNED_P (vtrue)
+	       != SUBREG_PROMOTED_UNSIGNED_P (vfalse))
+	      && (SUBREG_PROMOTED_SIGNED_P (vtrue)
+		  != SUBREG_PROMOTED_SIGNED_P (vfalse))))
+
 	return NULL_RTX;
 
       promoted_target = gen_reg_rtx (GET_MODE (reg_vtrue));
@@ -1463,7 +1466,7 @@  noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
 
       target = gen_rtx_SUBREG (GET_MODE (vtrue), promoted_target, byte_vtrue);
       SUBREG_PROMOTED_VAR_P (target) = SUBREG_PROMOTED_VAR_P (vtrue);
-      SUBREG_PROMOTED_UNSIGNED_SET (target, SUBREG_PROMOTED_UNSIGNED_P (vtrue));
+      SUBREG_PROMOTED_SET (target, SUBREG_PROMOTED_GET (vtrue));
       emit_move_insn (x, target);
       return x;
     }
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 78f59d6..4e0b964 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -584,12 +584,12 @@  ubsan_expand_si_overflow_mul_check (gimple stmt)
 	  if (GET_CODE (lopart0) == SUBREG)
 	    {
 	      SUBREG_PROMOTED_VAR_P (lopart0) = 1;
-	      SUBREG_PROMOTED_UNSIGNED_SET (lopart0, 0);
+	      SUBREG_PROMOTED_SET (lopart0, 0);
 	    }
 	  if (GET_CODE (lopart1) == SUBREG)
 	    {
 	      SUBREG_PROMOTED_VAR_P (lopart1) = 1;
-	      SUBREG_PROMOTED_UNSIGNED_SET (lopart1, 0);
+	      SUBREG_PROMOTED_SET (lopart1, 0);
 	    }
 	  tree halfstype = build_nonstandard_integer_type (hprec, 0);
 	  ops.op0 = make_tree (halfstype, lopart0);
diff --git a/gcc/optabs.c b/gcc/optabs.c
index ca1c194..a00b383 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -368,7 +368,7 @@  widen_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode,
      a promoted object differs from our extension.  */
   if (! no_extend
       || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)
-	  && SUBREG_PROMOTED_UNSIGNED_P (op) == unsignedp))
+	  && SUBREG_CHECK_PROMOTED_SIGN (op, unsignedp)))
     return convert_modes (mode, oldmode, op, unsignedp);
 
   /* If MODE is no wider than a single word, we return a lowpart or paradoxical
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 6ec91a8..edb449b 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1585,29 +1585,71 @@  get_full_set_src_cost (rtx x, struct full_rtx_costs *c)
 #define SUBREG_PROMOTED_VAR_P(RTX)					\
   (RTL_FLAG_CHECK1 ("SUBREG_PROMOTED", (RTX), SUBREG)->in_struct)
 
-#define SUBREG_PROMOTED_UNSIGNED_SET(RTX, VAL)				\
-do {									\
-  rtx const _rtx = RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_SET",	\
-				    (RTX), SUBREG);			\
-  if ((VAL) < 0)							\
-    _rtx->volatil = 1;							\
-  else {								\
-    _rtx->volatil = 0;							\
-    _rtx->unchanging = (VAL);						\
-  }									\
-} while (0)
-
 /* Valid for subregs which are SUBREG_PROMOTED_VAR_P().  In that case
    this gives the necessary extensions:
-   0  - signed
-   1  - normal unsigned
+   0  - signed (SPR_SIGNED)
+   1  - normal unsigned (SPR_UNSIGNED)
+   2  - value is both sign and unsign extended for mode
+	(SPR_SIGNED_AND_UNSIGNED).
    -1 - pointer unsigned, which most often can be handled like unsigned
         extension, except for generating instructions where we need to
-	emit special code (ptr_extend insns) on some architectures.  */
+	emit special code (ptr_extend insns) on some architectures
+	(SPR_POINTER). */
+
+const unsigned int SRP_POINTER	= -1;
+const unsigned int SRP_SIGNED   = 0;
+const unsigned int SRP_UNSIGNED = 1;
+const unsigned int SRP_SIGNED_AND_UNSIGNED = 2;
+
+/* Sets promoted mode for SUBREG_PROMOTED_VAR_P().  */
+#define SUBREG_PROMOTED_SET(RTX, VAL)		                        \
+do {								        \
+  rtx const _rtx = RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_SET",		\
+                                    (RTX), SUBREG);			\
+  switch ((VAL))							\
+  {									\
+    case SRP_POINTER:							\
+      _rtx->volatil = 0;						\
+      _rtx->unchanging = 0;						\
+      break;								\
+    case SRP_SIGNED:							\
+      _rtx->volatil = 0;						\
+      _rtx->unchanging = 1;						\
+      break;								\
+    case SRP_UNSIGNED:							\
+      _rtx->volatil = 1;						\
+      _rtx->unchanging = 0;						\
+      break;								\
+    case SRP_SIGNED_AND_UNSIGNED:					\
+      _rtx->volatil = 1;						\
+      _rtx->unchanging = 1;						\
+      break;								\
+  }									\
+} while (0)
 
+/* Gets promoted mode for SUBREG_PROMOTED_VAR_P().  */
+#define SUBREG_PROMOTED_GET(RTX)	\
+  (2 * (RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_GET", (RTX), SUBREG)->volatil)\
+   + (RTX)->unchanging - 1)
+
+/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
+   for SIGNED type.  */
+#define SUBREG_PROMOTED_SIGNED_P(RTX)	\
+  (RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_SIGNED_P", (RTX), SUBREG)->unchanging == 1)
+
+/* Predicate to check if RTX of SUBREG_PROMOTED_VAR_P() is promoted
+   for UNSIGNED type.  In case of SRP_POINTER, SUBREG_PROMOTED_UNSIGNED_P
+   returns -1 as this is in most cases handled like unsigned extension,
+   except for generating instructions where special code is emitted for
+   (ptr_extend insns) on some architectures.  */
 #define SUBREG_PROMOTED_UNSIGNED_P(RTX)	\
-  ((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil) \
-   ? -1 : (int) (RTX)->unchanging)
+  ((((RTL_FLAG_CHECK1 ("SUBREG_PROMOTED_UNSIGNED_P", (RTX), SUBREG)->volatil)\
+     + (RTX)->unchanging) == 0) ? -1 : ((RTX)->volatil == 1))
+
+/* Checks if RTX of SUBREG_PROMOTED_VAR_P() is promotd for given SIGN.  */
+#define	SUBREG_CHECK_PROMOTED_SIGN(RTX, SIGN) \
+     ((SIGN) ? SUBREG_PROMOTED_UNSIGNED_P ((RTX))	\
+	     : SUBREG_PROMOTED_SIGNED_P ((RTX)))	\
 
 /* True if the subreg was generated by LRA for reload insns.  Such
    subregs are valid only during LRA.  */
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 82cfc1bf..547bdbf 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -4619,7 +4619,7 @@  num_sign_bit_copies1 (const_rtx x, enum machine_mode mode, const_rtx known_x,
 	 and we are looking at it in a wider mode, we know that at least the
 	 high-order bits are known to be sign bit copies.  */
 
-      if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
+      if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_SIGNED_P (x))
 	{
 	  num0 = cached_num_sign_bit_copies (SUBREG_REG (x), mode,
 					     known_x, known_mode, known_ret);
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 181b56f..81d196f 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -1352,7 +1352,7 @@  simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
 	 target mode is the same as the variable's promotion.  */
       if (GET_CODE (op) == SUBREG
 	  && SUBREG_PROMOTED_VAR_P (op)
-	  && ! SUBREG_PROMOTED_UNSIGNED_P (op)
+	  && SUBREG_PROMOTED_SIGNED_P (op)
 	  && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
 	{
 	  temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
@@ -5595,8 +5595,7 @@  simplify_subreg (enum machine_mode outermode, rtx op,
 	      && subreg_lowpart_p (newx))
 	    {
 	      SUBREG_PROMOTED_VAR_P (newx) = 1;
-	      SUBREG_PROMOTED_UNSIGNED_SET
-		(newx, SUBREG_PROMOTED_UNSIGNED_P (op));
+	      SUBREG_PROMOTED_SET (newx, SUBREG_PROMOTED_GET (op));
 	    }
 	  return newx;
 	}