[llvm-branch-commits] [llvm-gcc-branch] r76143 - in /llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc: c-common.c c-parser.c c-typeck.c config/asm.h config/i386/i386.c config/i386/i386.h cp/parser.c llvm-convert.cpp testsuite/g++.apple/asm-block-54.C testsuite/gcc.apple/asm-block-54.c

Bill Wendling isanbard at gmail.com
Thu Jul 16 19:17:28 PDT 2009


Author: void
Date: Thu Jul 16 21:17:21 2009
New Revision: 76143

URL: http://llvm.org/viewvc/llvm-project?rev=76143&view=rev
Log:
--- Merging r74342 into '.':
U    gcc/llvm-convert.cpp
--- Merging r74544 into '.':
G    gcc/llvm-convert.cpp
--- Merging r74545 into '.':
G    gcc/llvm-convert.cpp
--- Merging r74570 into '.':
G    gcc/llvm-convert.cpp
--- Merging r74575 into '.':
G    gcc/llvm-convert.cpp
--- Merging r74721 into '.':
G    gcc/llvm-convert.cpp
--- Merging r74723 into '.':
G    gcc/llvm-convert.cpp
--- Merging r75068 into '.':
U    gcc/cp/parser.c
U    gcc/c-common.c
U    gcc/c-parser.c
U    gcc/config/asm.h
--- Merging r75078 into '.':
G    gcc/c-common.c
--- Merging r75140 into '.':
G    gcc/c-common.c
--- Merging r75171 into '.':
U    gcc/testsuite/gcc.apple/asm-block-54.c
U    gcc/testsuite/g++.apple/asm-block-54.C
--- Merging r75306 into '.':
U    gcc/config/i386/i386.h
--- Merging r75555 into '.':
G    gcc/llvm-convert.cpp
--- Merging r75681 into '.':
G    gcc/llvm-convert.cpp
U    gcc/config/i386/i386.c
--- Merging r75715 into '.':
U    gcc/c-typeck.c
G    gcc/c-common.c

Modified:
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-common.c
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-parser.c
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-typeck.c
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/asm.h
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.c
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.h
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/cp/parser.c
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/llvm-convert.cpp
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/g++.apple/asm-block-54.C
    llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/gcc.apple/asm-block-54.c

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-common.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-common.c?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-common.c (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-common.c Thu Jul 16 21:17:21 2009
@@ -286,6 +286,10 @@
 int flag_iasm_blocks;
 /* APPLE LOCAL end CW asm blocks */
 
+/* LLVM LOCAL begin CW asm blocks */
+int iasm_label_counter;
+/* LLVM LOCAL end CW asm blocks */
+
 /* Nonzero means to treat bitfields as signed unless they say `unsigned'.  */
 
 int flag_signed_bitfields = 1;
@@ -2602,31 +2606,34 @@
 #ifdef ENABLE_LLVM
     }
 
-  /* In LLVM we want to represent this as &P[i], not as P+i*sizeof(*P). */
-  /* Convert the pointer to char* if it is a pointer to a zero sized object. */
-  if (!size_set)
-    ptrop = convert(build_pointer_type(char_type_node), ptrop);
-  
-  /* If the code is a subtract, construct 0-(ptrdiff_t)val. */
-  if (resultcode == MINUS_EXPR)
-    intop = build_binary_op (MINUS_EXPR,
-                             convert (ssizetype, integer_zero_node),
-                             convert (ssizetype, intop), 1);
-  {
-    tree arrayref, result, folded;
-    arrayref = build4 (ARRAY_REF, TREE_TYPE(TREE_TYPE(ptrop)), ptrop, intop,
-                       NULL_TREE, NULL_TREE);
-    result = build_unary_op (ADDR_EXPR, arrayref, 0);
-  
-    folded = fold (result);
-    if (folded == result)
-      TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
-    
-    /* If the original was void* + int, we converted it to char* + int.  Convert
-       back to the appropriate void* result and match type qualifiers. */
-    if (!size_set || TYPE_QUALS(result_type) != TYPE_QUALS(TREE_TYPE(folded)))
-      folded = convert(result_type, folded);
-    return folded;
+  if (!inside_iasm_block) {
+    /* In LLVM we want to represent this as &P[i], not as P+i*sizeof(*P). */
+    /* Convert the pointer to char* if it is a pointer to a zero sized object.*/
+    if (!size_set)
+      ptrop = convert(build_pointer_type(char_type_node), ptrop);
+
+    /* If the code is a subtract, construct 0-(ptrdiff_t)val. */
+    if (resultcode == MINUS_EXPR)
+      intop = build_binary_op (MINUS_EXPR,
+                               convert (ssizetype, integer_zero_node),
+                               convert (ssizetype, intop), 1);
+    {
+      tree arrayref, result, folded;
+      arrayref = build4 (ARRAY_REF, TREE_TYPE(TREE_TYPE(ptrop)), ptrop, intop,
+                         NULL_TREE, NULL_TREE);
+      result = build_unary_op (ADDR_EXPR, arrayref, 0);
+
+      folded = fold (result);
+      if (folded == result)
+        TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
+
+      /* If the original was void* + int, we converted it to char* + int.
+         Convert back to the appropriate void* result and match type 
+         qualifiers. */
+      if (!size_set || TYPE_QUALS(result_type) != TYPE_QUALS(TREE_TYPE(folded)))
+        folded = convert(result_type, folded);
+      return folded;
+    }
   }
 #endif
   /* LLVM LOCAL end */
@@ -8305,6 +8312,20 @@
 	  sprintf (buf + strlen (buf), "%s", name);
 	  break;
 	}
+/* LLVM LOCAL begin */
+#ifdef ENABLE_LLVM
+      /* Labels defined earlier in the asm block will have DECL_INITIAL set
+         at this point; labels we haven't seen yet won't.  LABEL_DECL_UID
+         should be set in either case (when we saw the forward ref, we
+         assumed the target was inside the block; that's what gcc does). */
+      if (DECL_INITIAL (arg))
+        sprintf(buf + strlen(buf), HOST_WIDE_INT_PRINT_DEC "b",
+                LABEL_DECL_UID (arg));
+      else
+        sprintf(buf + strlen(buf), HOST_WIDE_INT_PRINT_DEC "f",
+                LABEL_DECL_UID (arg));
+#else
+/* LLVM LOCAL end */
       TREE_USED (arg) = 1;
       IASM_OFFSET_PREFIX (e, buf);
       arg = build1 (ADDR_EXPR, ptr_type_node, arg);
@@ -8330,6 +8351,8 @@
 #endif
       iasm_get_register_var (arg, modifier, buf, argnum, must_be_reg, e);
       iasm_force_constraint (0, e);
+/* LLVM LOCAL */
+#endif  /* ENABLE_LLVM */
       break;
 
     case IDENTIFIER_NODE:
@@ -8628,16 +8651,15 @@
 tree
 iasm_label (tree labid, bool atsign)
 {
-/* LLVM LOCAL begin */
-/* Unused variables resulting from code change below. */
-#ifdef ENABLE_LLVM
-  tree stmt, label;
-#else
   tree sexpr;
   tree inputs = NULL_TREE, outputs = NULL_TREE, clobbers = NULL_TREE;
   tree stmt;
+/* LLVM LOCAL begin */
+#ifndef ENABLE_LLVM
   tree label, l;
   tree str, one;
+#else
+  tree label;
 #endif
 /* LLVM LOCAL end */
   STRIP_NOPS (labid);
@@ -8650,8 +8672,7 @@
 
   iasm_buffer[0] = '\0';
   label = iasm_define_label (labid);
-/* LLVM LOCAL */
-#ifdef ENABLE_LLVM
+#if 0
   /* Ideally I'd like to do this, but, it moves the label in:
 
 	nop
@@ -8676,6 +8697,8 @@
 #else
   /* Arrange for the label to be a parameter to the ASM_EXPR, as only then will the
      backend `manage it' for us, say, making a unique copy for inline expansion.  */
+/* LLVM LOCAL */
+#ifndef ENABLE_LLVM
   sprintf (iasm_buffer, "%%l0: # %s", IDENTIFIER_POINTER (DECL_NAME (label)));
 
   l = build1 (ADDR_EXPR, ptr_type_node, label);
@@ -8687,6 +8710,13 @@
   inputs = chainon (NULL_TREE, one);
   sexpr = build_string (strlen (iasm_buffer), iasm_buffer);
   
+/* LLVM LOCAL begin */
+#else
+  sprintf (iasm_buffer, HOST_WIDE_INT_PRINT_DEC ": # %s",
+           LABEL_DECL_UID (label), IDENTIFIER_POINTER (DECL_NAME (label)));
+  sexpr = build_string (strlen (iasm_buffer), iasm_buffer);
+#endif
+/* LLVM LOCAL end */
   /* Simple asm statements are treated as volatile.  */
   stmt = build_stmt (ASM_EXPR, sexpr, outputs, inputs, clobbers, NULL_TREE);
   ASM_VOLATILE_P (stmt) = 1;
@@ -8826,6 +8856,10 @@
   strcat (buf, labname);
   newid = get_identifier (buf);
   newid = lookup_label (newid);
+/* LLVM LOCAL begin */  
+  if (LABEL_DECL_UID (newid) == -1)
+    LABEL_DECL_UID (newid) = iasm_label_counter++;
+/* LLVM LOCAL end */
   return newid;
 }
 
@@ -8853,6 +8887,10 @@
   strcat (buf, labname);
   newid = get_identifier (buf);
   newid = define_label (input_location, newid);
+  /* LLVM LOCAL begin */
+  if (LABEL_DECL_UID (newid) == -1)
+    LABEL_DECL_UID (newid) = iasm_label_counter++;
+  /* LLVM LOCAL end */
   return newid;
 }
 

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-parser.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-parser.c?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-parser.c (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-parser.c Thu Jul 16 21:17:21 2009
@@ -4122,6 +4122,8 @@
 	  iasm_state = iasm_asm;
 	  inside_iasm_block = true;
 	  iasm_kill_regs = true;
+          /* LLVM LOCAL */
+          iasm_label_counter = 0;
 	  iasm_in_decl = false;
 	  c_parser_iasm_line_seq_opt (parser);
 	  stmt = NULL_TREE;
@@ -9021,6 +9023,8 @@
   iasm_state = iasm_asm;
   inside_iasm_block = true;
   iasm_kill_regs = true;
+  /* LLVM LOCAL */
+  iasm_label_counter = 0;
   stmt = c_begin_compound_stmt (true);
   /* Parse an (optional) statement-seq.  */
   c_parser_iasm_line_seq_opt (parser);
@@ -9041,6 +9045,8 @@
   iasm_state = iasm_asm;
   inside_iasm_block = true;
   iasm_kill_regs = true;
+  /* LLVM LOCAL */
+  iasm_label_counter = 0;
   stmt = c_begin_compound_stmt (true);
   if (!c_parser_iasm_bol (parser))
     {    

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-typeck.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-typeck.c?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-typeck.c (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/c-typeck.c Thu Jul 16 21:17:21 2009
@@ -3331,7 +3331,12 @@
 
       /* LLVM LOCAL begin */
       /* LLVM wants &x[y] to be kept as an &x[y] for better optimization. */
-#ifndef ENABLE_LLVM
+      /* However we shouldn't do this in asm blocks; we aren't going to be
+         doing anything complicated with addresses, and the asm block code
+         only understands array refs. */
+#ifdef ENABLE_LLVM
+      if (inside_iasm_block) {
+#endif
       /* For &x[y], return x+y */
       if (TREE_CODE (arg) == ARRAY_REF)
 	{
@@ -3344,6 +3349,8 @@
 				   : op0),
 				  TREE_OPERAND (arg, 1), 1);
 	}
+#ifdef ENABLE_LLVM
+      }
 #endif 
       /* LLVM LOCAL end */
 

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/asm.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/asm.h?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/asm.h (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/asm.h Thu Jul 16 21:17:21 2009
@@ -25,6 +25,8 @@
 extern bool iasm_kill_regs;
 extern bool iasm_in_operands;
 extern tree iasm_do_id (tree);
+/* LLVM LOCAL */
+extern int iasm_label_counter;
 /* Maximum number of arguments.  */
 #define IASM_MAX_ARG 11
 

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.c?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.c (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.c Thu Jul 16 21:17:21 2009
@@ -22060,9 +22060,18 @@
       enum machine_mode mode = VOIDmode;
       if (IDENTIFIER_POINTER (arg)[1] == 'e')
 	mode = SImode;
+/* LLVM LOCAL begin */
+/* Accept H registers for LLVM, this totally obviates need for ASM_USES. */
+#ifndef ENABLE_LLVM
       else if (/* IDENTIFIER_POINTER (arg)[2] == 'h'
 		  || */ IDENTIFIER_POINTER (arg)[2] == 'l')
 	mode = QImode;
+#else
+      else if (IDENTIFIER_POINTER (arg)[2] == 'h'
+               || IDENTIFIER_POINTER (arg)[2] == 'l')
+	mode = QImode;
+#endif
+/* LLVM LOCAL end */
       else if (IDENTIFIER_POINTER (arg)[2] == 'x')
 	mode = HImode;
       else if (IDENTIFIER_POINTER (arg)[1] == 'r')

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.h?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.h (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/config/i386/i386.h Thu Jul 16 21:17:21 2009
@@ -2512,6 +2512,7 @@
 #define IASM_SEE_NO_IMMEDIATE(E)			\
   E->as_immediate = false
 
+/* LLVM LOCAL begin change some = to + */
 /* Table of instructions that need extra constraints.  Keep this table sorted.  */
 #undef TARGET_IASM_OP_CONSTRAINT
 #define TARGET_IASM_OP_CONSTRAINT \
@@ -2592,81 +2593,81 @@
   { "cmovz", 2, "rm"},		\
   { "cmp", 1, rm8 "," rm16 "," rm32 C RM64 "," r8 "," r16 "," r32 C R64},\
   { "cmp", 2, ri8 "," ri16 "," ri32 C RI64 "," m8 "," m16 "," m32 C M64},\
-  { "cmpeqpd", 1, "=x"},	\
+  { "cmpeqpd", 1, "+x"},	\
   { "cmpeqpd", 2, "xm"},	\
-  { "cmpeqps", 1, "=x"},	\
+  { "cmpeqps", 1, "+x"},	\
   { "cmpeqps", 2, "xm"},	\
-  { "cmpeqsd", 1, "=x"},	\
+  { "cmpeqsd", 1, "+x"},	\
   { "cmpeqsd", 2, "xm"},	\
-  { "cmpeqss", 1, "=x"},	\
+  { "cmpeqss", 1, "+x"},	\
   { "cmpeqss", 2, "xm"},	\
-  { "cmplepd", 1, "=x"},	\
+  { "cmplepd", 1, "+x"},	\
   { "cmplepd", 2, "xm"},	\
-  { "cmpleps", 1, "=x"},	\
+  { "cmpleps", 1, "+x"},	\
   { "cmpleps", 2, "xm"},	\
-  { "cmplesd", 1, "=x"},	\
+  { "cmplesd", 1, "+x"},	\
   { "cmplesd", 2, "xm"},	\
-  { "cmpless", 1, "=x"},	\
+  { "cmpless", 1, "+x"},	\
   { "cmpless", 2, "xm"},	\
-  { "cmpltpd", 1, "=x"},	\
+  { "cmpltpd", 1, "+x"},	\
   { "cmpltpd", 2, "xm"},	\
-  { "cmpltps", 1, "=x"},	\
+  { "cmpltps", 1, "+x"},	\
   { "cmpltps", 2, "xm"},	\
-  { "cmpltsd", 1, "=x"},	\
+  { "cmpltsd", 1, "+x"},	\
   { "cmpltsd", 2, "xm"},	\
-  { "cmpltss", 1, "=x"},	\
+  { "cmpltss", 1, "+x"},	\
   { "cmpltss", 2, "xm"},	\
-  { "cmpneqpd", 1, "=x"},	\
+  { "cmpneqpd", 1, "+x"},	\
   { "cmpneqpd", 2, "xm"},	\
-  { "cmpneqps", 1, "=x"},	\
+  { "cmpneqps", 1, "+x"},	\
   { "cmpneqps", 2, "xm"},	\
-  { "cmpneqsd", 1, "=x"},	\
+  { "cmpneqsd", 1, "+x"},	\
   { "cmpneqsd", 2, "xm"},	\
-  { "cmpneqss", 1, "=x"},	\
+  { "cmpneqss", 1, "+x"},	\
   { "cmpneqss", 2, "xm"},	\
-  { "cmpnlepd", 1, "=x"},	\
+  { "cmpnlepd", 1, "+x"},	\
   { "cmpnlepd", 2, "xm"},	\
-  { "cmpnleps", 1, "=x"},	\
+  { "cmpnleps", 1, "+x"},	\
   { "cmpnleps", 2, "xm"},	\
-  { "cmpnlesd", 1, "=x"},	\
+  { "cmpnlesd", 1, "+x"},	\
   { "cmpnlesd", 2, "xm"},	\
-  { "cmpnless", 1, "=x"},	\
+  { "cmpnless", 1, "+x"},	\
   { "cmpnless", 2, "xm"},	\
-  { "cmpnltpd", 1, "=x"},	\
+  { "cmpnltpd", 1, "+x"},	\
   { "cmpnltpd", 2, "xm"},	\
-  { "cmpnltps", 1, "=x"},	\
+  { "cmpnltps", 1, "+x"},	\
   { "cmpnltps", 2, "xm"},	\
-  { "cmpnltsd", 1, "=x"},	\
+  { "cmpnltsd", 1, "+x"},	\
   { "cmpnltsd", 2, "xm"},	\
-  { "cmpnltss", 1, "=x"},	\
+  { "cmpnltss", 1, "+x"},	\
   { "cmpnltss", 2, "xm"},	\
-  { "cmpordpd", 1, "=x"},	\
+  { "cmpordpd", 1, "+x"},	\
   { "cmpordpd", 2, "xm"},	\
-  { "cmpordps", 1, "=x"},	\
+  { "cmpordps", 1, "+x"},	\
   { "cmpordps", 2, "xm"},	\
-  { "cmpordsd", 1, "=x"},	\
+  { "cmpordsd", 1, "+x"},	\
   { "cmpordsd", 2, "xm"},	\
-  { "cmpordss", 1, "=x"},	\
+  { "cmpordss", 1, "+x"},	\
   { "cmpordss", 2, "xm"},	\
-  { "cmppd", 1, "=x"},		\
+  { "cmppd", 1, "+x"},		\
   { "cmppd", 2, "xm"},		\
   { "cmppd", 3, "i"},		\
-  { "cmpps", 1, "=x"},		\
+  { "cmpps", 1, "+x"},		\
   { "cmpps", 2, "xm"},		\
   { "cmpps", 3, "i"},		\
-  { "cmpsd", 1, "=x"},		\
+  { "cmpsd", 1, "+x"},		\
   { "cmpsd", 2, "xm"},		\
   { "cmpsd", 3, "i"},		\
-  { "cmpss", 1, "=x"},		\
+  { "cmpss", 1, "+x"},		\
   { "cmpss", 2, "xm"},		\
   { "cmpss", 3, "i"},		\
-  { "cmpunordpd", 1, "=x"},	\
+  { "cmpunordpd", 1, "+x"},	\
   { "cmpunordpd", 2, "xm"},	\
-  { "cmpunordps", 1, "=x"},	\
+  { "cmpunordps", 1, "+x"},	\
   { "cmpunordps", 2, "xm"},	\
-  { "cmpunordsd", 1, "=x"},	\
+  { "cmpunordsd", 1, "+x"},	\
   { "cmpunordsd", 2, "xm"},	\
-  { "cmpunordss", 1, "=x"},	\
+  { "cmpunordss", 1, "+x"},	\
   { "cmpunordss", 2, "xm"},	\
   { "cmpxchg", 1, "+mr"},      	\
   { "cmpxchg", 2, "r"},      	\
@@ -2783,9 +2784,9 @@
   { "fldcw", 1, m16},		\
   { "fldenv", 1, "m"},		\
   { "fldt", 1, "m"},		\
-  { "fmul", 1, "=f,t,@"},	\
+  { "fmul", 1, "+f,t,@"},	\
   { "fmul", 2, "t,f," m32fpm64fp},\
-  { "fmulp", 1, "=f"},		\
+  { "fmulp", 1, "+f"},		\
   { "fmulp", 2, "t"},		\
   { "fnsave", 1, "=m"},		\
   { "fnstcw", 1, "m"},		\
@@ -2798,9 +2799,9 @@
   { "fstenv", 1, "=m"},		\
   { "fstp", 1, "=f" m32fpm64fpm80fp},\
   { "fstsw", 1, "=ma"},       	\
-  { "fsub", 1, "=f,t,@"},	\
+  { "fsub", 1, "+f,t,@"},	\
   { "fsub", 2, "t,f," m32fpm64fp},\
-  { "fsubr", 1, "=f,t," m32fpm64fp},\
+  { "fsubr", 1, "+f,t," m32fpm64fp},\
   { "fsubr", 2, "t,f,@"},	\
   { "fucom", 1, "f"},		\
   { "fucomi", 1, "t"},		\
@@ -2977,13 +2978,13 @@
   { "movzx", 1, "=" r16 "," r32},\
   { "movzx", 2, rm8 "," rm8rm16},\
   { "mul", 1, rm8rm16rm32},	\
-  { "mulpd", 1, "=x"},		\
+  { "mulpd", 1, "+x"},		\
   { "mulpd", 2, "xm"},		\
-  { "mulps", 1, "=x"},		\
+  { "mulps", 1, "+x"},		\
   { "mulps", 2, "xm"},		\
-  { "mulsd", 1, "=x"},		\
+  { "mulsd", 1, "+x"},		\
   { "mulsd", 2, "xm"},		\
-  { "mulss", 1, "=x"},		\
+  { "mulss", 1, "+x"},		\
   { "mulss", 2, "xm"},		\
   { "neg", 1, "+" rm8rm16rm32},	\
   { "not", 1, "+" rm8rm16rm32},	\
@@ -3042,7 +3043,7 @@
   { "pextrw", 1, "=" r32R64},	\
   { "pextrw", 2, "xy"},		\
   { "pextrw", 3, "i"},		\
-  { "pinsrw", 1, "=xy"},	\
+  { "pinsrw", 1, "+xy"},	\
   { "pinsrw", 2, r32R64 "m"},	\
   { "pinsrw", 3, "i"},		\
   { "pmaddwd", 1, "+x,y"},	\
@@ -3263,6 +3264,7 @@
   { "xorpd", 2, "xm"},		\
   { "xorps", 1, "+x"},		\
   { "xorps", 2, "xm"},
+/* LLVM LOCAL end change some = to + */
 
 #define TARGET_IASM_EXTRA_CLOBBERS \
   { "rdtsc", { "edx", "eax"} }

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/cp/parser.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/cp/parser.c?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/cp/parser.c (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/cp/parser.c Thu Jul 16 21:17:21 2009
@@ -7095,6 +7095,8 @@
       iasm_state = iasm_asm;
       inside_iasm_block = true;
       iasm_kill_regs = true;
+      /* LLVM LOCAL */
+      iasm_label_counter = 0;
       cp_parser_iasm_line_seq_opt (parser);
       iasm_state = iasm_none;
       iasm_end_block ();
@@ -18063,6 +18065,8 @@
   iasm_state = iasm_asm;
   inside_iasm_block = true;
   iasm_kill_regs = true;
+  /* LLVM LOCAL */
+  iasm_label_counter = 0;
   if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
     return error_mark_node;
   /* Begin the compound-statement.  */
@@ -18087,6 +18091,8 @@
   iasm_state = iasm_asm;
   inside_iasm_block = true;
   iasm_kill_regs = true;
+  /* LLVM LOCAL */
+  iasm_label_counter = 0;
   /* Begin the compound-statement.  */
   compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
   if (!cp_lexer_iasm_bol (parser->lexer))

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/llvm-convert.cpp?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/llvm-convert.cpp Thu Jul 16 21:17:21 2009
@@ -3900,19 +3900,250 @@
   return Result;
 }
 
+/// See if operand "exp" can use the indicated Constraint (which is
+/// terminated by a null or a comma).
+/// Returns:  -1=no, 0=yes but auxiliary instructions needed, 1=yes and free
+int MatchWeight(const char *Constraint, tree Operand, bool isInput) {
+  const char *p = Constraint;
+  int RetVal = 0;
+  // Look for hard register operand.  This matches only a constraint of a
+  // register class that includes that hard register, and it matches that
+  // perfectly, so we never return 0 in this case.
+  if (TREE_CODE(Operand) == VAR_DECL && DECL_HARD_REGISTER(Operand)) {
+    int RegNum = decode_reg_name(extractRegisterName(Operand));
+    RetVal = -1;
+    if (RegNum >= 0) {
+      do {
+        unsigned RegClass;
+        if (*p == 'r')
+          RegClass = GENERAL_REGS;
+        else
+          RegClass = REG_CLASS_FROM_CONSTRAINT(*p, p);
+        if (RegClass != NO_REGS &&
+            TEST_HARD_REG_BIT(reg_class_contents[RegClass], RegNum)) {
+          RetVal = 1;
+          break;
+        }
+        ++p;
+      } while (*p != ',' && *p != 0);
+    }
+  }
+  // Look for integer constant operand.  This cannot match "m", and "i" is
+  // better than "r".  FIXME target-dependent immediate letters are not handled
+  // yet; in general they require looking at the value.
+  if (TREE_CODE(Operand) == INTEGER_CST) {
+    do {
+      RetVal = -1;
+      if (*p == 'i' || *p == 'n') {     // integer constant
+        RetVal = 1;
+        break;
+      }
+      if (*p != 'm' && *p != 'o' && *p != 'V')    // not memory
+        RetVal = 0;
+      ++p;
+    } while (*p != ',' && *p != 0);
+  }
+  /// TEMPORARY.  This has the effect that alternative 0 is always chosen,
+  /// except in the cases handled above.
+  return RetVal;
+}
+
+/// ChooseConstraintTuple: we know each of the NumInputs+NumOutputs strings
+/// in Constraints[] is a comma-separated list of NumChoices different
+/// constraints.  Look through the operands and constraint possibilities
+/// and pick a tuple where all the operands match.  Replace the strings
+/// in Constraints[] with the shorter strings from that tuple (malloc'ed,
+/// caller is responsible for cleaning it up).  Later processing can alter what
+/// Constraints points to, so to make sure we delete everything, the addresses
+/// of everything we allocated also are returned in ReplacementStrings.
+/// Casting back and forth from char* to const char* is Ugly, but we have to
+/// interface with C code that expects const char*.
+///
+/// gcc's algorithm for picking "the best" tuple is quite complicated, and
+/// is performed after things like SROA, not before.  At the moment we are
+/// just trying to pick one that will work.  This may get refined.
+static void
+ChooseConstraintTuple (const char **Constraints, tree exp, unsigned NumInputs,
+                      unsigned NumOutputs, unsigned NumChoices,
+                      const char **ReplacementStrings)
+{
+  int MaxWeight = -1;
+  unsigned int CommasToSkip = 0;
+  int *Weights = (int *)alloca(NumChoices * sizeof(int));
+  // RunningConstraints is pointers into the Constraints strings which
+  // are incremented as we go to point to the beginning of each
+  // comma-separated alternative.
+  const char** RunningConstraints = 
+    (const char**)alloca((NumInputs+NumOutputs)*sizeof(const char*));
+  memcpy(RunningConstraints, Constraints, 
+         (NumInputs+NumOutputs) * sizeof(const char*));
+  // The entire point of this loop is to compute CommasToSkip.
+  for (unsigned int i=0; i<NumChoices; i++) {
+    Weights[i] = 0;
+    unsigned int j = 0;
+    for (tree Output = ASM_OUTPUTS(exp); j<NumOutputs;
+         j++, Output = TREE_CHAIN(Output)) {
+      if (i==0)
+        RunningConstraints[j]++;    // skip leading =
+      const char* p = RunningConstraints[j];
+      while (*p=='*' || *p=='&' || *p=='%')   // skip modifiers
+        p++;
+      if (Weights[i] != -1) {
+        int w = MatchWeight(p, TREE_VALUE(Output), false);
+        // Nonmatch means the entire tuple doesn't match.  However, we
+        // keep scanning to set up RunningConstraints correctly for the
+        // next tuple.
+        if (w < 0)
+          Weights[i] = -1;
+        else 
+          Weights[i] += w;
+      }
+      while (*p!=0 && *p!=',')
+        p++;
+      if (*p!=0) {
+        p++;      // skip comma
+        while (*p=='*' || *p=='&' || *p=='%')
+          p++;    // skip modifiers
+      }
+      RunningConstraints[j] = p;
+    }
+    assert(j==NumOutputs);
+    for (tree Input = ASM_INPUTS(exp); j<NumInputs+NumOutputs; 
+         j++, Input = TREE_CHAIN(Input)) {
+      const char* p = RunningConstraints[j];
+      if (Weights[i] != -1) {
+        int w = MatchWeight(p, TREE_VALUE(Input), true);
+        if (w < 0)
+          Weights[i] = -1;    // As above.
+        else
+          Weights[i] += w;
+      }
+      while (*p!=0 && *p!=',')
+        p++;
+      if (*p!=0)
+        p++;
+      RunningConstraints[j] = p;
+    }
+    if (Weights[i]>MaxWeight) {
+      CommasToSkip = i;
+      MaxWeight = Weights[i];
+    }
+  }
+  // We have picked an alternative (the CommasToSkip'th one).
+  // Change Constraints to point to malloc'd copies of the appropriate
+  // constraints picked out of the original strings.
+  for (unsigned int i=0; i<NumInputs+NumOutputs; i++) {
+    assert(*(RunningConstraints[i])==0);   // sanity check
+    const char* start = Constraints[i];
+    if (i<NumOutputs)
+      start++;          // skip '=' or '+'
+    const char* end = start;
+    while (*end != ',' && *end != 0)
+      end++;
+    for (unsigned int j=0; j<CommasToSkip; j++) {
+      start = end+1;
+      end = start;
+      while (*end != ',' && *end != 0)
+        end++;
+    }
+    // String we want is at start..end-1 inclusive.
+    // For outputs, copy the leading = or +.
+    char *newstring;
+    if (i<NumOutputs) {
+      newstring = (char *)xmalloc(end-start+1+1);
+      newstring[0] = *(Constraints[i]);
+      strncpy(newstring+1, start, end-start);
+      newstring[end-start+1] = 0;
+    } else {
+      newstring = (char *)xmalloc(end-start+1);
+      strncpy(newstring, start, end-start);
+      newstring[end-start] = 0;
+    }
+    Constraints[i] = (const char *)newstring;
+    ReplacementStrings[i] = (const char*)newstring;
+  }
+}
+
+static void FreeConstTupleStrings(const char **ReplacementStrings,
+                                  unsigned int Size) {
+  for (unsigned int i=0; i<Size; i++)
+    free((char *)ReplacementStrings[i]);
+}
 
 Value *TreeToLLVM::EmitASM_EXPR(tree exp) {
   unsigned NumInputs = list_length(ASM_INPUTS(exp));
   unsigned NumOutputs = list_length(ASM_OUTPUTS(exp));
   unsigned NumInOut = 0;
-  
+
+  // Look for multiple alternative constraints: multiple alternatives separated
+  // by commas.
+  unsigned NumChoices = 0;    // sentinal; real value is always at least 1.
+  const char* p;
+  for (tree t = ASM_INPUTS(exp); t; t = TREE_CHAIN(t)) {
+    unsigned NumInputChoices = 1;
+    for (p = TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(t))); *p; p++) {
+      if (*p == ',')
+        NumInputChoices++;
+    }
+    if (NumChoices==0)
+      NumChoices = NumInputChoices;
+    else if (NumChoices != NumInputChoices)
+      abort();      // invalid constraints
+  }
+  for (tree t = ASM_OUTPUTS(exp); t; t = TREE_CHAIN(t)) {
+    unsigned NumOutputChoices = 1;
+    for (p = TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(t))); *p; p++) {
+      if (*p == ',')
+        NumOutputChoices++;
+    }
+    if (NumChoices==0)
+      NumChoices = NumOutputChoices;
+    else if (NumChoices != NumOutputChoices)
+      abort();      // invalid constraints
+  }
+ 
   /// Constraints - The output/input constraints, concatenated together in array
   /// form instead of list form.
   const char **Constraints =
     (const char **)alloca((NumOutputs + NumInputs) * sizeof(const char *));
   
-  // FIXME: CHECK ALTERNATIVES, something akin to check_operand_nalternatives.
-  
+  // Process outputs.
+  int ValNum = 0;
+  for (tree Output = ASM_OUTPUTS(exp); Output; 
+       Output = TREE_CHAIN(Output), ++ValNum) {
+    tree Operand = TREE_VALUE(Output);
+    tree type = TREE_TYPE(Operand);
+    // If there's an erroneous arg, emit no insn.
+    if (type == error_mark_node) return 0;
+    
+    // Parse the output constraint.
+    const char *Constraint =
+      TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Output)));
+    Constraints[ValNum] = Constraint;
+  }
+  // Process inputs.
+  for (tree Input = ASM_INPUTS(exp); Input; Input = TREE_CHAIN(Input),++ValNum){
+    tree Val = TREE_VALUE(Input);
+    tree type = TREE_TYPE(Val);
+    // If there's an erroneous arg, emit no insn.
+    if (type == error_mark_node) return 0;
+    
+    const char *Constraint =
+      TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Input)));
+    Constraints[ValNum] = Constraint;
+  }
+
+  // If there are multiple constraint tuples, pick one.  Constraints is
+  // altered to point to shorter strings (which are malloc'ed), and everything
+  // below Just Works as in the NumChoices==1 case.
+  const char** ReplacementStrings = 0;
+  if (NumChoices>1) {
+    ReplacementStrings =
+      (const char **)alloca((NumOutputs + NumInputs) * sizeof(const char *));
+    ChooseConstraintTuple(Constraints, exp, NumInputs, NumOutputs, NumChoices,
+                          ReplacementStrings);
+  }
+
   std::vector<Value*> CallOps;
   std::vector<const Type*> CallArgTypes;
   std::string NewAsmStr = ConvertInlineAsmStr(exp, NumOutputs+NumInputs);
@@ -3924,26 +4155,24 @@
   SmallVector<bool, 4> CallResultIsSigned;
   
   // Process outputs.
-  int ValNum = 0;
+  ValNum = 0;
   for (tree Output = ASM_OUTPUTS(exp); Output; 
        Output = TREE_CHAIN(Output), ++ValNum) {
     tree Operand = TREE_VALUE(Output);
     tree type = TREE_TYPE(Operand);
-    // If there's an erroneous arg, emit no insn.
-    if (type == error_mark_node) return 0;
     
     // Parse the output constraint.
-    const char *Constraint =
-      TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Output)));
-    Constraints[ValNum] = Constraint;
+    const char *Constraint = Constraints[ValNum];
     bool IsInOut, AllowsReg, AllowsMem;
     if (!parse_output_constraint(&Constraint, ValNum, NumInputs, NumOutputs,
-                                 &AllowsMem, &AllowsReg, &IsInOut))
+                                 &AllowsMem, &AllowsReg, &IsInOut)) {
+      if (NumChoices>1)
+        FreeConstTupleStrings(ReplacementStrings, NumInputs+NumOutputs);
       return 0;
-    
+    }    
     assert(Constraint[0] == '=' && "Not an output constraint?");
 
-    // Output constraints must be addressible if they aren't simple register
+    // Output constraints must be addressable if they aren't simple register
     // constraints (this emits "address of register var" errors, etc).
     if (!AllowsReg && (AllowsMem || IsInOut))
       lang_hooks.mark_addressable(Operand);
@@ -3956,13 +4185,17 @@
     // If this output register is pinned to a machine register, use that machine
     // register instead of the specified constraint.
     if (TREE_CODE(Operand) == VAR_DECL && DECL_HARD_REGISTER(Operand)) {
-      int RegNum = decode_reg_name(extractRegisterName(Operand));
+      const char* RegName = extractRegisterName(Operand);
+      int RegNum = decode_reg_name(RegName);
       if (RegNum >= 0) {
-        unsigned RegNameLen = strlen(reg_names[RegNum]);
+        // Constraints don't have the leading %, the variable names do
+        if (*RegName == '%')
+          RegName++;
+        unsigned RegNameLen = strlen(RegName);
         char *NewConstraint = (char*)alloca(RegNameLen+4);
         NewConstraint[0] = '=';
         NewConstraint[1] = '{';
-        memcpy(NewConstraint+2, reg_names[RegNum], RegNameLen);
+        memcpy(NewConstraint+2, RegName, RegNameLen);
         NewConstraint[RegNameLen+2] = '}';
         NewConstraint[RegNameLen+3] = 0;
         SimplifiedConstraint = NewConstraint;
@@ -4001,19 +4234,17 @@
   for (tree Input = ASM_INPUTS(exp); Input; Input = TREE_CHAIN(Input),++ValNum){
     tree Val = TREE_VALUE(Input);
     tree type = TREE_TYPE(Val);
-    // If there's an erroneous arg, emit no insn.
-    if (type == error_mark_node) return 0;
     
-    const char *Constraint =
-      TREE_STRING_POINTER(TREE_VALUE(TREE_PURPOSE(Input)));
-    Constraints[ValNum] = Constraint;
+    const char *Constraint = Constraints[ValNum];
 
     bool AllowsReg, AllowsMem;
     if (!parse_input_constraint(Constraints+ValNum, ValNum-NumOutputs,
                                 NumInputs, NumOutputs, NumInOut,
-                                Constraints, &AllowsMem, &AllowsReg))
+                                Constraints, &AllowsMem, &AllowsReg)) {
+      if (NumChoices>1)
+        FreeConstTupleStrings(ReplacementStrings, NumInputs+NumOutputs);
       return 0;
-    
+    }    
     bool isIndirect = false;
     if (AllowsReg || !AllowsMem) {    // Register operand.
       const Type *LLVMTy = ConvertType(type);
@@ -4066,6 +4297,8 @@
             error("%Hunsupported inline asm: input constraint with a matching "
                   "output constraint of incompatible type!",
                   &EXPR_LOCATION(exp));
+            if (NumChoices>1)
+              FreeConstTupleStrings(ReplacementStrings, NumInputs+NumOutputs);
             return 0;
           }
           unsigned OTyBits = TD.getTypeSizeInBits(OTy);
@@ -4105,25 +4338,29 @@
     
     // If this output register is pinned to a machine register, use that machine
     // register instead of the specified constraint.
-    int RegNum;
-    if (TREE_CODE(Val) == VAR_DECL && DECL_HARD_REGISTER(Val) &&
-        (RegNum = decode_reg_name(extractRegisterName(Val))) >= 0) {
-      ConstraintStr += '{';
-      ConstraintStr += reg_names[RegNum];
-      ConstraintStr += '}';
-    } else {
-      // If there is a simpler form for the register constraint, use it.
-      std::string Simplified = CanonicalizeConstraint(Constraint);
-      ConstraintStr += Simplified;
+    if (TREE_CODE(Val) == VAR_DECL && DECL_HARD_REGISTER(Val)) {
+      const char *RegName = extractRegisterName(Val);
+      int RegNum = decode_reg_name(RegName);
+      if (RegNum >= 0) {
+        if (*RegName == '%')      // Variables have leading %.
+          RegName++;              // Constraints don't.
+        ConstraintStr += '{';
+        ConstraintStr += RegName;
+        ConstraintStr += '}';
+        continue;
+      }
     }
+
+    // If there is a simpler form for the register constraint, use it.
+    std::string Simplified = CanonicalizeConstraint(Constraint);
+    ConstraintStr += Simplified;
   }
   
-  if (ASM_USES(exp)) {
-    // FIXME: Figure out what ASM_USES means.
-    error("%Hcode warrior/ms asm not supported yet in %qs", &EXPR_LOCATION(exp),
-          TREE_STRING_POINTER(ASM_STRING(exp)));
-    return 0;
-  }
+  // ASM_USES contains info about certain hard regs which are used as inputs.
+  // gcc represents the xH registers on x86 this way because of deficiencies
+  // in the way gcc can represent registers internally.  llvm-gcc can represent
+  // these as normal inputs, so we aren't using ASM_USES.
+  assert(ASM_USES(exp)==0);
   
   // Process clobbers.
 
@@ -4139,6 +4376,8 @@
     case -2:     // Invalid.
       error("%Hunknown register name %qs in %<asm%>", &EXPR_LOCATION(exp), 
             RegName);
+      if (NumChoices>1)
+        FreeConstTupleStrings(ReplacementStrings, NumInputs+NumOutputs);
       return 0;
     case -3:     // cc
       ConstraintStr += ",~{cc}";
@@ -4147,8 +4386,10 @@
       ConstraintStr += ",~{memory}";
       break;
     default:     // Normal register name.
+      if (*RegName == '%')
+        RegName++;
       ConstraintStr += ",~{";
-      ConstraintStr += reg_names[RegCode];
+      ConstraintStr += RegName;
       ConstraintStr += "}";
       break;
     }
@@ -4175,6 +4416,8 @@
   // Make sure we're created a valid inline asm expression.
   if (!InlineAsm::Verify(FTy, ConstraintStr)) {
     error("%HInvalid or unsupported inline assembly!", &EXPR_LOCATION(exp));
+    if (NumChoices>1)
+      FreeConstTupleStrings(ReplacementStrings, NumInputs+NumOutputs);
     return 0;
   }
   
@@ -4200,6 +4443,8 @@
   if (const TargetAsmInfo *TAI = TheTarget->getTargetAsmInfo())
     TAI->ExpandInlineAsm(CV);
   
+  if (NumChoices>1)
+    FreeConstTupleStrings(ReplacementStrings, NumInputs+NumOutputs);
   return 0;
 }
 

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/g++.apple/asm-block-54.C
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/g%2B%2B.apple/asm-block-54.C?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/g++.apple/asm-block-54.C (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/g++.apple/asm-block-54.C Thu Jul 16 21:17:21 2009
@@ -2,7 +2,8 @@
 /* APPLE LOCAL x86_64 */
 /* { dg-require-effective-target ilp32 } */
 /* { dg-options { -fasm-blocks -msse3 } } */
-/* { dg-final { scan-assembler "movq -\(16|36\)\\\(%ebp\\\), %mm0" } } */
+/* LLVM LOCAL */
+/* { dg-final { scan-assembler "movq -\(16|36|24\)\\\(%ebp\\\), %mm0" } } */
 /* Radar 4515069 */
 
 void foo() {

Modified: llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/gcc.apple/asm-block-54.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/gcc.apple/asm-block-54.c?rev=76143&r1=76142&r2=76143&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/gcc.apple/asm-block-54.c (original)
+++ llvm-gcc-4.2/branches/Apple/Bender-SWB/gcc/testsuite/gcc.apple/asm-block-54.c Thu Jul 16 21:17:21 2009
@@ -1,7 +1,8 @@
 /* { dg-do compile { target i?86*-*-darwin* } } */
 /* { dg-require-effective-target ilp32 } */
 /* { dg-options { -fasm-blocks -msse3 } } */
-/* { dg-final { scan-assembler "movq -\(16|36\)\\\(%ebp\\\), %mm0" } } */
+/* LLVM LOCAL */
+/* { dg-final { scan-assembler "movq -\(16|36|24\)\\\(%ebp\\\), %mm0" } } */
 /* Radar 4515069 */
 
 void foo() {





More information about the llvm-branch-commits mailing list