diff mbox

[PING^1,AArch64] Implement Bitwise AND and Set Flags

Message ID F3068DEED1A463459E0887A091B1549312354668@BY2PRD0710MB364.namprd07.prod.outlook.com
State New
Headers show

Commit Message

Hurugalawadi, Naveen March 26, 2013, 10:06 a.m. UTC
Hi,

Thanks for reviewing the patch and testcase.

There were some doubts regarding the addressing modes supported by 
these instructions.
The only source that could be referred was the AARCH64 assembler.
Hence, these modifications are implemented as per the assembler.
Please let me know if there should be any modifications.

>> the second "set" in each pattern should have the "=r,rk" constraint
>> rather than just "=r,r".
If the destination operand is stack register, assembler generates error
as follows:-
Error: operand 1 should be an integer register -- `ands sp,x0,x1' 
The ands instruction does not support sp in any of the operand as per
the assembler. 

adds and subs instruction can use SP as the first operand.
adds    x2, sp, 1                  -> No Assembler error
subs    x3, sp, #1                -> No Assembler error
adds    x2, sp, x1                -> No Assembler error
subs    x3, sp, x1                -> No Assembler error
adds    x3, sp, x1, lsl 3        -> No Assembler error
subs    x3, sp, x1, lsl 3        -> No Assembler error
Hence, their implementations are modified to support stack pointer as
the first operand.

>> I've attached a patch that provides more thorough test cases,
>> including execute ones. 
Thanks for the testcase. They were added in the testsuite and run to
check the implementation. However, the testcase had shift operations in
them. Hence, the pattern for shift are added in the patch.
Testcase have been added for adds and subs instructions similar to
the ands testcase submitted by Ian.

Please review the same and let me know if there should be any 
modifications in the patch.

Build and tested on aarch64-thunder-elf (using Cavium's internal
simulator). 

Thanks,
Naveen

gcc/

2013-03-26   Naveen H.S  <Naveen.Hurugalawadi@caviumnetworks.com>

	* config/aarch64/aarch64.md (*add<mode>3_compare0): Use stack
	register in constraint of 1st operand along with general registers.
	(*addsi3_compare0_uxtw): Likewise.
	(*sub<mode>3_compare0): Likewise.
	(*subsi3_compare0_uxtw): Likewise.
	(*adds_<shift>_<mode>, *adds_<shift>_si_uxtw): New pattern.
	(*adds_mul_imm_<mode>, *adds_mul_imm_si_uxtw): New pattern.
	(*subs_<shift>_<mode>, *subs_<shift>_si_uxtw): New pattern.
	(*subs_mul_imm_<mode>, *subs_mul_imm_si_uxtw): New pattern.
	(*and<mode>3_compare0, *andsi3_compare0_si_uxtw): New pattern.
	(*ands_<shift>_<mode>, *ands_<shift>_si_uxtw): New pattern.

gcc/testsuite/

2013-03-26   Naveen H.S  <Naveen.Hurugalawadi@caviumnetworks.com>

	* gcc.target/aarch64/ands.c: New.
	* gcc.target/aarch64/adds1.c: New.
	* gcc.target/aarch64/adds2.c: New.
	* gcc.target/aarch64/subs1.c: New.
	* gcc.target/aarch64/subs2.c: New.

Comments

Marcus Shawcroft March 26, 2013, 10:17 a.m. UTC | #1
On 26/03/13 10:06, Hurugalawadi, Naveen wrote:
>>> >>the second "set" in each pattern should have the "=r,rk" constraint
>>> >>rather than just "=r,r".
> If the destination operand is stack register, assembler generates error
> as follows:-
> Error: operand 1 should be an integer register -- `ands sp,x0,x1'
> The ands instruction does not support sp in any of the operand as per
> the assembler.
>
> adds and subs instruction can use SP as the first operand.
> adds    x2, sp, 1                  -> No Assembler error
> subs    x3, sp, #1                -> No Assembler error
> adds    x2, sp, x1                -> No Assembler error
> subs    x3, sp, x1                -> No Assembler error
> adds    x3, sp, x1, lsl 3        -> No Assembler error
> subs    x3, sp, x1, lsl 3        -> No Assembler error
> Hence, their implementations are modified to support stack pointer as
> the first operand.
>

Umm, I think Ian meant 'K' rather than 'k', these patterns should be 
able to deal with constants in the 2nd operand. The SP is irrelevant here.

/M
Marcus Shawcroft March 26, 2013, 10:58 a.m. UTC | #2
On 26/03/13 10:17, Marcus Shawcroft wrote:
> On 26/03/13 10:06, Hurugalawadi, Naveen wrote:
>>>>>> the second "set" in each pattern should have the "=r,rk" constraint
>>>>>> rather than just "=r,r".
>> If the destination operand is stack register, assembler generates error
>> as follows:-
>> Error: operand 1 should be an integer register -- `ands sp,x0,x1'
>> The ands instruction does not support sp in any of the operand as per
>> the assembler.
>>
>> adds and subs instruction can use SP as the first operand.
>> adds    x2, sp, 1                  -> No Assembler error
>> subs    x3, sp, #1                -> No Assembler error
>> adds    x2, sp, x1                -> No Assembler error
>> subs    x3, sp, x1                -> No Assembler error
>> adds    x3, sp, x1, lsl 3        -> No Assembler error
>> subs    x3, sp, x1, lsl 3        -> No Assembler error
>> Hence, their implementations are modified to support stack pointer as
>> the first operand.
>>
>
> Umm, I think Ian meant 'K' rather than 'k', these patterns should be
> able to deal with constants in the 2nd operand. The SP is irrelevant here.
>
> /M
>
>
Hi,

Ignore my last comment.  This patch now has two changes in it, the 
original 'and' patch with test case and the modification to add/sub 
patterns with test cases.  Can we split them into two different patches 
please. Just and in one, add/sub in the other.


Thanks
/Marcus
diff mbox

Patch

--- gcc/config/aarch64/aarch64.md	2013-03-26 12:51:12.180448029 +0530
+++ gcc/config/aarch64/aarch64.md	2013-03-26 13:38:48.792544909 +0530
@@ -1256,7 +1256,7 @@ 
 (define_insn "*add<mode>3_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
 	(compare:CC_NZ
-	 (plus:GPI (match_operand:GPI 1 "register_operand" "%r,r")
+	 (plus:GPI (match_operand:GPI 1 "register_operand" "%rk,rk")
 		   (match_operand:GPI 2 "aarch64_plus_operand" "rI,J"))
 	 (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=r,r")
@@ -1273,7 +1273,7 @@ 
 (define_insn "*addsi3_compare0_uxtw"
   [(set (reg:CC_NZ CC_REGNUM)
 	(compare:CC_NZ
-	 (plus:SI (match_operand:SI 1 "register_operand" "%r,r")
+	 (plus:SI (match_operand:SI 1 "register_operand" "%rk,rk")
 		  (match_operand:SI 2 "aarch64_plus_operand" "rI,J"))
 	 (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=r,r")
@@ -1286,6 +1286,146 @@ 
    (set_attr "mode" "SI")]
 )
 
+(define_insn "*adds_<shift>_<mode>"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (plus:GPI (ASHIFT:GPI
+		    (match_operand:GPI 1 "register_operand" "r")
+		    (match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
+		   (match_operand:GPI 3 "register_operand" "r"))
+	 (const_int 0)))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+	(plus:GPI (ASHIFT:GPI (match_dup 1) (match_dup 2))
+		  (match_dup 3)))]
+  ""
+  "adds\\t%<w>0, %<w>3, %<w>1, <shift> %2"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of above
+(define_insn "*adds_<shift>_si_uxtw"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (plus:SI (ASHIFT:SI
+		   (match_operand:SI 1 "register_operand" "r")
+		   (match_operand:QI 2 "aarch64_shift_imm_si" "n"))
+		  (match_operand:SI 3 "register_operand" "r"))
+	 (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=r")
+	(zero_extend:DI (plus:SI (ASHIFT:SI (match_dup 1) (match_dup 2))
+				 (match_dup 3))))]
+  ""
+  "adds\\t%w0, %w3, %w1, <shift> %2"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*adds_mul_imm_<mode>"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (plus:GPI (mult:GPI
+		    (match_operand:GPI 1 "register_operand" "r")
+		    (match_operand:QI 2 "aarch64_pwr_2_<mode>" "n"))
+		   (match_operand:GPI 3 "register_operand" "rk"))
+	 (const_int 0)))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+	(plus:GPI (mult:GPI (match_dup 1) (match_dup 2))
+		  (match_dup 3)))]
+  ""
+  "adds\\t%<w>0, %<w>3, %<w>1, lsl %p2"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of above
+(define_insn "*adds_mul_imm_si_uxtw"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (plus:SI (mult:SI
+		   (match_operand:SI 1 "register_operand" "r")
+		   (match_operand:QI 2 "aarch64_pwr_2_si" "n"))
+		  (match_operand:SI 3 "register_operand" "rk"))
+	 (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=r")
+	(zero_extend:DI (plus:SI (mult:SI (match_dup 1) (match_dup 2))
+				 (match_dup 3))))]
+  ""
+  "adds\\t%w0, %w3, %w1, lsl %p2"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*subs_<shift>_<mode>"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (minus:GPI (match_operand:GPI 1 "register_operand" "r")
+		    (ASHIFT:GPI
+		     (match_operand:GPI 2 "register_operand" "r")
+		     (match_operand:QI 3 "aarch64_shift_imm_<mode>" "n")))
+	 (const_int 0)))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+	(minus:GPI (match_dup 1)
+		   (ASHIFT:GPI (match_dup 2) (match_dup 3))))]
+  ""
+  "subs\\t%<w>0, %<w>1, %<w>2, <shift> %3"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of above
+(define_insn "*subs_<shift>_si_uxtw"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (minus:SI (match_operand:SI 1 "register_operand" "r")
+		   (ASHIFT:SI
+		    (match_operand:SI 2 "register_operand" "r")
+		    (match_operand:QI 3 "aarch64_shift_imm_si" "n")))
+	(const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=r")
+	(zero_extend:DI (minus:SI (match_dup 1)
+				  (ASHIFT:SI (match_dup 2) (match_dup 3)))))]
+  ""
+  "subs\\t%w0, %w1, %w2, <shift> %3"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*subs_mul_imm_<mode>"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (minus:GPI (match_operand:GPI 1 "register_operand" "rk")
+		    (mult:GPI
+		     (match_operand:GPI 2 "register_operand" "r")
+		     (match_operand:QI 3 "aarch64_pwr_2_<mode>" "n")))
+	 (const_int 0)))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+	(minus:GPI (match_dup 1)
+		   (mult:GPI (match_dup 2) (match_dup 3))))]
+  ""
+  "subs\\t%<w>0, %<w>1, %<w>2, lsl %p3"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of above
+(define_insn "*subs_mul_imm_si_uxtw"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (minus:SI (match_operand:SI 1 "register_operand" "rk")
+		   (mult:SI
+		    (match_operand:SI 2 "register_operand" "r")
+		    (match_operand:QI 3 "aarch64_pwr_2_si" "n")))
+	 (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=r")
+	(zero_extend:DI (minus:SI (match_dup 1)
+				  (mult:SI (match_dup 2) (match_dup 3)))))]
+  ""
+  "subs\\t%w0, %w1, %w2, lsl %p3"
+  [(set_attr "v8type" "alu_shift")
+   (set_attr "mode" "SI")]
+)
+
 (define_insn "*add<mode>3nr_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
 	(compare:CC_NZ
@@ -1633,7 +1773,7 @@ 
 
 (define_insn "*sub<mode>3_compare0"
   [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ (minus:GPI (match_operand:GPI 1 "register_operand" "r")
+	(compare:CC_NZ (minus:GPI (match_operand:GPI 1 "register_operand" "rk")
 				  (match_operand:GPI 2 "register_operand" "r"))
 		       (const_int 0)))
    (set (match_operand:GPI 0 "register_operand" "=r")
@@ -1647,7 +1787,7 @@ 
 ;; zero_extend version of above
 (define_insn "*subsi3_compare0_uxtw"
   [(set (reg:CC_NZ CC_REGNUM)
-	(compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "r")
+	(compare:CC_NZ (minus:SI (match_operand:SI 1 "register_operand" "rk")
 				 (match_operand:SI 2 "register_operand" "r"))
 		       (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=r")
@@ -2433,6 +2573,70 @@ 
   [(set_attr "v8type" "logic,logic_imm")
    (set_attr "mode" "SI")])
 
+(define_insn "*and<mode>3_compare0"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (and:GPI (match_operand:GPI 1 "register_operand" "%r,r")
+		  (match_operand:GPI 2 "aarch64_logical_operand" "r,<lconst>"))
+	 (const_int 0)))
+   (set (match_operand:GPI 0 "register_operand" "=r,r")
+	(and:GPI (match_dup 1) (match_dup 2)))]
+  ""
+  "ands\\t%<w>0, %<w>1, %<w>2"
+  [(set_attr "v8type" "logic,logic_imm")
+   (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of above
+(define_insn "*andsi3_compare0_si_uxtw"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (and:SI (match_operand:SI 1 "register_operand" "%r,r")
+		 (match_operand:SI 2 "aarch64_logical_operand" "r,K"))
+	 (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=r,r")
+	(zero_extend:DI (and:SI (match_dup 1) (match_dup 2))))]
+  ""
+  "ands\\t%w0, %w1, %w2"
+  [(set_attr "v8type" "logic,logic_imm")
+   (set_attr "mode" "SI")]
+)
+
+(define_insn "*ands_<shift>_<mode>"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (and:GPI (ASHIFT:GPI
+		   (match_operand:GPI 1 "register_operand" "r")
+		   (match_operand:QI 2 "aarch64_shift_imm_<mode>" "n"))
+		  (match_operand:GPI 3 "register_operand" "r"))
+	 (const_int 0)))
+   (set (match_operand:GPI 0 "register_operand" "=r")
+	(and:GPI (ASHIFT:GPI (match_dup 1) (match_dup 2))
+		 (match_dup 3)))]
+  ""
+  "ands\\t%<w>0, %<w>3, %<w>1, <shift> %2"
+  [(set_attr "v8type" "logics_shift")
+   (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of above
+(define_insn "*ands_<shift>_si_uxtw"
+  [(set (reg:CC_NZ CC_REGNUM)
+	(compare:CC_NZ
+	 (and:SI (ASHIFT:SI
+		  (match_operand:SI 1 "register_operand" "r")
+		  (match_operand:QI 2 "aarch64_shift_imm_si" "n"))
+		 (match_operand:SI 3 "register_operand" "r"))
+	 (const_int 0)))
+   (set (match_operand:DI 0 "register_operand" "=r")
+	(zero_extend:DI (and:SI (ASHIFT:SI (match_dup 1) (match_dup 2))
+				(match_dup 3))))]
+  ""
+  "ands\\t%w0, %w3, %w1, <shift> %2"
+  [(set_attr "v8type" "logics_shift")
+   (set_attr "mode" "SI")]
+)
+
 (define_insn "*<LOGICAL:optab>_<SHIFT:optab><mode>3"
   [(set (match_operand:GPI 0 "register_operand" "=r")
 	(LOGICAL:GPI (SHIFT:GPI
--- gcc/testsuite/gcc.target/aarch64/adds1.c	1970-01-01 05:30:00.000000000 +0530
+++ gcc/testsuite/gcc.target/aarch64/adds1.c	2013-03-26 13:38:48.792544909 +0530
@@ -0,0 +1,149 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 --save-temps" } */
+
+extern void abort (void);
+
+int
+adds_si_test1 (int a, int b, int c)
+{
+  int d = a + b;
+
+  /* { dg-final { scan-assembler "adds\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+adds_si_test2 (int a, int b, int c)
+{
+  int d = a + 0xff;
+
+  /* { dg-final { scan-assembler "adds\tw\[0-9\]+, w\[0-9\]+, 255" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+adds_si_test3 (int a, int b, int c)
+{
+  int d = a + (b << 3);
+
+  /* { dg-final { scan-assembler "adds\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+typedef long long s64;
+
+s64
+adds_di_test1 (s64 a, s64 b, s64 c)
+{
+  s64 d = a + b;
+
+  /* { dg-final { scan-assembler "adds\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+adds_di_test2 (s64 a, s64 b, s64 c)
+{
+  s64 d = a + 0xff;
+
+  /* { dg-final { scan-assembler "adds\tx\[0-9\]+, x\[0-9\]+, 255" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+adds_di_test3 (s64 a, s64 b, s64 c)
+{
+  s64 d = a + (b << 3);
+
+  /* { dg-final { scan-assembler "adds\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int main ()
+{
+  int x;
+  s64 y;
+
+  x = adds_si_test1 (29, 4, 5);
+  if (x != 42)
+    abort ();
+
+  x = adds_si_test1 (5, 2, 20);
+  if (x != 29)
+    abort ();
+
+  x = adds_si_test2 (29, 4, 5);
+  if (x != 293)
+    abort ();
+
+  x = adds_si_test2 (1024, 2, 20);
+  if (x != 1301)
+    abort ();
+
+  x = adds_si_test3 (35, 4, 5);
+  if (x != 76)
+    abort ();
+
+  x = adds_si_test3 (5, 2, 20);
+  if (x != 43)
+    abort ();
+
+  y = adds_di_test1 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+
+  if (y != 0xc75050536)
+    abort ();
+
+  y = adds_di_test1 (0x5000500050005ll,
+		     0x2111211121112ll,
+		     0x0000000002020ll);
+  if (y != 0x9222922294249)
+    abort ();
+
+  y = adds_di_test2 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+  if (y != 0x955050631)
+    abort ();
+
+  y = adds_di_test2 (0x130002900ll,
+		     0x320000004ll,
+		     0x505050505ll);
+  if (y != 0x955052f08)
+    abort ();
+
+  y = adds_di_test3 (0x130000029ll,
+		     0x064000008ll,
+		     0x505050505ll);
+  if (y != 0x9b9050576)
+    abort ();
+
+  y = adds_di_test3 (0x130002900ll,
+		     0x088000008ll,
+		     0x505050505ll);
+  if (y != 0xafd052e4d)
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { cleanup-saved-temps } } */
--- gcc/testsuite/gcc.target/aarch64/adds2.c	1970-01-01 05:30:00.000000000 +0530
+++ gcc/testsuite/gcc.target/aarch64/adds2.c	2013-03-26 13:38:48.792544909 +0530
@@ -0,0 +1,155 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 --save-temps" } */
+
+extern void abort (void);
+
+int
+adds_si_test1 (int a, int b, int c)
+{
+  int d = a + b;
+
+  /* { dg-final { scan-assembler-not "adds\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+  /* { dg-final { scan-assembler "add\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+adds_si_test2 (int a, int b, int c)
+{
+  int d = a + 0xfff;
+
+  /* { dg-final { scan-assembler-not "adds\tw\[0-9\]+, w\[0-9\]+, 4095" } } */
+  /* { dg-final { scan-assembler "add\tw\[0-9\]+, w\[0-9\]+, 4095" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+adds_si_test3 (int a, int b, int c)
+{
+  int d = a + (b << 3);
+
+  /* { dg-final { scan-assembler-not "adds\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "add\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+typedef long long s64;
+
+s64
+adds_di_test1 (s64 a, s64 b, s64 c)
+{
+  s64 d = a + b;
+
+  /* { dg-final { scan-assembler-not "adds\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+  /* { dg-final { scan-assembler "add\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+adds_di_test2 (s64 a, s64 b, s64 c)
+{
+  s64 d = a + 0x1000ll;
+
+  /* { dg-final { scan-assembler-not "adds\tx\[0-9\]+, x\[0-9\]+, 4096" } } */
+  /* { dg-final { scan-assembler "add\tx\[0-9\]+, x\[0-9\]+, 4096" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+adds_di_test3 (s64 a, s64 b, s64 c)
+{
+  s64 d = a + (b << 3);
+
+  /* { dg-final { scan-assembler-not "adds\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "add\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int main ()
+{
+  int x;
+  s64 y;
+
+  x = adds_si_test1 (29, 4, 5);
+  if (x != 42)
+    abort ();
+
+  x = adds_si_test1 (5, 2, 20);
+  if (x != 29)
+    abort ();
+
+  x = adds_si_test2 (29, 4, 5);
+  if (x != 4133)
+    abort ();
+
+  x = adds_si_test2 (1024, 2, 20);
+  if (x != 5141)
+    abort ();
+
+  x = adds_si_test3 (35, 4, 5);
+  if (x != 76)
+    abort ();
+
+  x = adds_si_test3 (5, 2, 20);
+  if (x != 43)
+    abort ();
+
+  y = adds_di_test1 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+
+  if (y != 0xc75050536)
+    abort ();
+
+  y = adds_di_test1 (0x5000500050005ll,
+		     0x2111211121112ll,
+		     0x0000000002020ll);
+  if (y != 0x9222922294249)
+    abort ();
+
+  y = adds_di_test2 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+  if (y != 0x955051532)
+    abort ();
+
+  y = adds_di_test2 (0x540004100ll,
+		     0x320000004ll,
+		     0x805050205ll);
+  if (y != 0x1065055309)
+    abort ();
+
+  y = adds_di_test3 (0x130000029ll,
+		     0x064000008ll,
+		     0x505050505ll);
+  if (y != 0x9b9050576)
+    abort ();
+
+  y = adds_di_test3 (0x130002900ll,
+		     0x088000008ll,
+		     0x505050505ll);
+  if (y != 0xafd052e4d)
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { cleanup-saved-temps } } */
--- gcc/testsuite/gcc.target/aarch64/ands.c	1970-01-01 05:30:00.000000000 +0530
+++ gcc/testsuite/gcc.target/aarch64/ands.c	2013-03-26 13:43:10.868553797 +0530
@@ -0,0 +1,30 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int z;
+int
+foo (int x, int y)
+{
+  int l = x & y;
+  if (l == 0)
+    return 5;
+
+  /* { dg-final { scan-assembler "ands\tw\[0-9\]" } } */
+  z = l ;
+  return 25;
+}
+
+typedef long long s64;
+
+s64 zz;
+s64
+foo2 (s64 x, s64 y)
+{
+  s64 l = x & y;
+  if (l < 0)
+    return 5;
+
+  /* { dg-final { scan-assembler "ands\tx\[0-9\]" } } */
+  zz = l ;
+  return 25;
+}
--- gcc/testsuite/gcc.target/aarch64/subs1.c	1970-01-01 05:30:00.000000000 +0530
+++ gcc/testsuite/gcc.target/aarch64/subs1.c	2013-03-26 13:38:48.792544909 +0530
@@ -0,0 +1,149 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 --save-temps" } */
+
+extern void abort (void);
+
+int
+subs_si_test1 (int a, int b, int c)
+{
+  int d = a - c;
+
+  /* { dg-final { scan-assembler "subs\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+subs_si_test2 (int a, int b, int c)
+{
+  int d = a - 0xff;
+
+  /* { dg-final { scan-assembler "subs\tw\[0-9\]+, w\[0-9\]+, #255" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+subs_si_test3 (int a, int b, int c)
+{
+  int d = a - (b << 3);
+
+  /* { dg-final { scan-assembler "subs\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+typedef long long s64;
+
+s64
+subs_di_test1 (s64 a, s64 b, s64 c)
+{
+  s64 d = a - c;
+
+  /* { dg-final { scan-assembler "subs\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+subs_di_test2 (s64 a, s64 b, s64 c)
+{
+  s64 d = a - 0xff;
+
+  /* { dg-final { scan-assembler "subs\tx\[0-9\]+, x\[0-9\]+, #255" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+subs_di_test3 (s64 a, s64 b, s64 c)
+{
+  s64 d = a - (b << 3);
+
+  /* { dg-final { scan-assembler "subs\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d == 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int main ()
+{
+  int x;
+  s64 y;
+
+  x = subs_si_test1 (29, 4, 5);
+  if (x != 33)
+    abort ();
+
+  x = subs_si_test1 (5, 2, 20);
+  if (x != 7)
+    abort ();
+
+  x = subs_si_test2 (29, 4, 5);
+  if (x != -217)
+    abort ();
+
+  x = subs_si_test2 (1024, 2, 20);
+  if (x != 791)
+    abort ();
+
+  x = subs_si_test3 (35, 4, 5);
+  if (x != 12)
+    abort ();
+
+  x = subs_si_test3 (5, 2, 20);
+  if (x != 11)
+    abort ();
+
+  y = subs_di_test1 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+
+  if (y != 0x45000002d)
+    abort ();
+
+  y = subs_di_test1 (0x5000500050005ll,
+		     0x2111211121112ll,
+		     0x0000000002020ll);
+  if (y != 0x7111711171117)
+    abort ();
+
+  y = subs_di_test2 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+  if (y != 0x955050433)
+    abort ();
+
+  y = subs_di_test2 (0x130002900ll,
+		     0x320000004ll,
+		     0x505050505ll);
+  if (y != 0x955052d0a)
+    abort ();
+
+  y = subs_di_test3 (0x130000029ll,
+		     0x064000008ll,
+		     0x505050505ll);
+  if (y != 0x3790504f6)
+    abort ();
+
+  y = subs_di_test3 (0x130002900ll,
+		     0x088000008ll,
+		     0x505050505ll);
+  if (y != 0x27d052dcd)
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { cleanup-saved-temps } } */
--- gcc/testsuite/gcc.target/aarch64/subs2.c	1970-01-01 05:30:00.000000000 +0530
+++ gcc/testsuite/gcc.target/aarch64/subs2.c	2013-03-26 13:38:48.792544909 +0530
@@ -0,0 +1,155 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 --save-temps" } */
+
+extern void abort (void);
+
+int
+subs_si_test1 (int a, int b, int c)
+{
+  int d = a - b;
+
+  /* { dg-final { scan-assembler-not "subs\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+  /* { dg-final { scan-assembler "sub\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+subs_si_test2 (int a, int b, int c)
+{
+  int d = a - 0xfff;
+
+  /* { dg-final { scan-assembler-not "subs\tw\[0-9\]+, w\[0-9\]+, #4095" } } */
+  /* { dg-final { scan-assembler "sub\tw\[0-9\]+, w\[0-9\]+, #4095" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int
+subs_si_test3 (int a, int b, int c)
+{
+  int d = a - (b << 3);
+
+  /* { dg-final { scan-assembler-not "subs\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "sub\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+, lsl 3" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+typedef long long s64;
+
+s64
+subs_di_test1 (s64 a, s64 b, s64 c)
+{
+  s64 d = a - b;
+
+  /* { dg-final { scan-assembler-not "subs\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+  /* { dg-final { scan-assembler "sub\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+subs_di_test2 (s64 a, s64 b, s64 c)
+{
+  s64 d = a - 0x1000ll;
+
+  /* { dg-final { scan-assembler-not "subs\tx\[0-9\]+, x\[0-9\]+, #4096" } } */
+  /* { dg-final { scan-assembler "sub\tx\[0-9\]+, x\[0-9\]+, #4096" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+s64
+subs_di_test3 (s64 a, s64 b, s64 c)
+{
+  s64 d = a - (b << 3);
+
+  /* { dg-final { scan-assembler-not "subs\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  /* { dg-final { scan-assembler "sub\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+, lsl 3" } } */
+  if (d <= 0)
+    return a + c;
+  else
+    return b + d + c;
+}
+
+int main ()
+{
+  int x;
+  s64 y;
+
+  x = subs_si_test1 (29, 4, 5);
+  if (x != 34)
+    abort ();
+
+  x = subs_si_test1 (5, 2, 20);
+  if (x != 25)
+    abort ();
+
+  x = subs_si_test2 (29, 4, 5);
+  if (x != 34)
+    abort ();
+
+  x = subs_si_test2 (1024, 2, 20);
+  if (x != 1044)
+    abort ();
+
+  x = subs_si_test3 (35, 4, 5);
+  if (x != 12)
+    abort ();
+
+  x = subs_si_test3 (5, 2, 20);
+  if (x != 25)
+    abort ();
+
+  y = subs_di_test1 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+
+  if (y != 0x63505052e)
+    abort ();
+
+  y = subs_di_test1 (0x5000500050005ll,
+		     0x2111211121112ll,
+		     0x0000000002020ll);
+  if (y != 0x5000500052025)
+    abort ();
+
+  y = subs_di_test2 (0x130000029ll,
+		     0x320000004ll,
+		     0x505050505ll);
+  if (y != 0x95504f532)
+    abort ();
+
+  y = subs_di_test2 (0x540004100ll,
+		     0x320000004ll,
+		     0x805050205ll);
+  if (y != 0x1065053309)
+    abort ();
+
+  y = subs_di_test3 (0x130000029ll,
+		     0x064000008ll,
+		     0x505050505ll);
+  if (y != 0x63505052e)
+    abort ();
+
+  y = subs_di_test3 (0x130002900ll,
+		     0x088000008ll,
+		     0x505050505ll);
+  if (y != 0x635052e05)
+    abort ();
+
+  return 0;
+}
+
+/* { dg-final { cleanup-saved-temps } } */