Index: gcc/gcc/builtins.c
===================================================================
--- gcc.orig/gcc/builtins.c
+++ gcc/gcc/builtins.c
@@ -5775,6 +5775,113 @@ expand_builtin_lock_release (enum machin
   emit_move_insn (mem, val);
 }
 
+#define LANE_CHECK(MODE, DIR, SUFFIX, ARGS)				\
+  if (vmode == MODE && nelems == 4)					\
+    emit_insn (gen_neon_v##DIR##4##SUFFIX ARGS);			\
+  else if (vmode == MODE && nelems == 3)				\
+    emit_insn (gen_neon_v##DIR##3##SUFFIX ARGS);			\
+  else if (vmode == MODE && nelems == 2)				\
+    emit_insn (gen_neon_v##DIR##2##SUFFIX ARGS)
+
+#define HACK_LANES(DIR, SUFFIX, TYPE, ARGS)				\
+  do									\
+    {									\
+      tree type;							\
+      enum machine_mode vmode;						\
+      unsigned HOST_WIDE_INT nelems;					\
+									\
+      type = (TYPE);							\
+      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);			\
+      vmode = TYPE_MODE (TREE_TYPE (type));				\
+      nelems = int_size_in_bytes (type) / GET_MODE_SIZE (vmode);	\
+      LANE_CHECK (V4HImode, DIR, SUFFIX##4hi, ARGS);			\
+      else LANE_CHECK (V8HImode, DIR, SUFFIX##8hi, ARGS);		\
+      else LANE_CHECK (V2SImode, DIR, SUFFIX##2si, ARGS);		\
+      else LANE_CHECK (V4SImode, DIR, SUFFIX##4si, ARGS);		\
+      else gcc_unreachable ();						\
+    }									\
+  while (0)
+
+static rtx
+expand_builtin_load_lanes (tree exp, rtx target)
+{
+  tree exp0;
+  rtx mem, addr;
+
+  exp0 = CALL_EXPR_ARG (exp, 0);
+  mem = expand_normal (exp0);
+  gcc_assert (MEM_P (mem));
+  addr = force_reg (Pmode, XEXP (mem, 0));
+  if (target == 0 || !REG_P (target))
+    target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
+  HACK_LANES (ld, v, TREE_TYPE (exp), (target, addr));
+  return target;
+}
+
+static rtx
+expand_builtin_load_lane (tree exp, rtx target)
+{
+  tree exp0, exp1, exp2;
+  rtx mem, addr, curval, lane;
+
+  exp0 = CALL_EXPR_ARG (exp, 0);
+  mem = expand_normal (exp0);
+  gcc_assert (MEM_P (mem));
+  addr = force_reg (Pmode, XEXP (mem, 0));
+
+  exp1 = CALL_EXPR_ARG (exp, 1);
+  curval = expand_normal (exp1);
+  curval = force_reg (TYPE_MODE (TREE_TYPE (exp1)), curval);
+
+  exp2 = CALL_EXPR_ARG (exp, 2);
+  lane = GEN_INT (tree_low_cst (exp2, 1));
+
+  if (target == 0 || !REG_P (target))
+    target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
+
+  HACK_LANES (ld, _lanev, TREE_TYPE (exp), (target, addr, curval, lane));
+  return target;
+}
+
+static rtx
+expand_builtin_store_lanes (tree exp, rtx target)
+{
+  tree exp0;
+  rtx addr, rhs;
+
+  exp0 = CALL_EXPR_ARG (exp, 0);
+  rhs = expand_normal (exp0);
+  rhs = force_reg (GET_MODE (rhs), rhs);
+
+  if (target == 0 || !MEM_P (target))
+    gcc_unreachable ();
+  addr = force_reg (Pmode, XEXP (target, 0));
+
+  HACK_LANES (st, v, TREE_TYPE (exp0), (addr, rhs));
+  return target;
+}
+
+static rtx
+expand_builtin_store_lane (tree exp, rtx target)
+{
+  tree exp0, exp1;
+  rtx addr, rhs, lane;
+
+  exp0 = CALL_EXPR_ARG (exp, 0);
+  rhs = expand_normal (exp0);
+  rhs = force_reg (GET_MODE (rhs), rhs);
+
+  exp1 = CALL_EXPR_ARG (exp, 1);
+  lane = GEN_INT (tree_low_cst (exp1, 1));
+
+  if (target == 0 || !MEM_P (target))
+    gcc_unreachable ();
+  addr = force_reg (Pmode, XEXP (target, 0));
+
+  HACK_LANES (st, _lanev, TREE_TYPE (exp0), (addr, rhs, lane));
+  return target;
+}
+
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
    (and in mode MODE if that's convenient).
@@ -6583,6 +6690,18 @@ expand_builtin (tree exp, rtx target, rt
       maybe_emit_free_warning (exp);
       break;
 
+    case BUILT_IN_LOAD_LANES:
+      return expand_builtin_load_lanes (exp, target);
+
+    case BUILT_IN_LOAD_LANE:
+      return expand_builtin_load_lane (exp, target);
+
+    case BUILT_IN_STORE_LANES:
+      return expand_builtin_store_lanes (exp, target);
+
+    case BUILT_IN_STORE_LANE:
+      return expand_builtin_store_lane (exp, target);
+
     default:	/* just do library call, if unknown builtin */
       break;
     }
Index: gcc/gcc/builtins.def
===================================================================
--- gcc.orig/gcc/builtins.def
+++ gcc/gcc/builtins.def
@@ -767,6 +767,11 @@ DEF_BUILTIN_STUB (BUILT_IN_EH_POINTER, "
 DEF_BUILTIN_STUB (BUILT_IN_EH_FILTER, "__builtin_eh_filter")
 DEF_BUILTIN_STUB (BUILT_IN_EH_COPY_VALUES, "__builtin_eh_copy_values")
 
+DEF_BUILTIN_STUB (BUILT_IN_LOAD_LANES, "__builtin_load_lanes")
+DEF_BUILTIN_STUB (BUILT_IN_STORE_LANES, "__builtin_store_lanes")
+DEF_BUILTIN_STUB (BUILT_IN_LOAD_LANE, "__builtin_load_lane")
+DEF_BUILTIN_STUB (BUILT_IN_STORE_LANE, "__builtin_store_lane")
+
 /* Synchronization Primitives.  */
 #include "sync-builtins.def"
 
Index: gcc/gcc/c-family/c-common.c
===================================================================
--- gcc.orig/gcc/c-family/c-common.c
+++ gcc/gcc/c-family/c-common.c
@@ -431,6 +431,11 @@ const struct c_common_resword c_common_r
   { "__decltype",       RID_DECLTYPE,   D_CXXONLY },
   { "__extension__",	RID_EXTENSION,	0 },
   { "__func__",		RID_C99_FUNCTION_NAME, 0 },
+  { "__load_lanes",	RID_LOAD_LANES,	0 },
+  { "__store_lanes",	RID_STORE_LANES, 0 },
+  { "__load_lane",	RID_LOAD_LANE,	0 },
+  { "__store_lane",	RID_STORE_LANE,	0 },
+  { "__array_ref",	RID_ARRAY_REF,	0 },
   { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, D_CXXONLY },
   { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, D_CXXONLY },
   { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, D_CXXONLY },
Index: gcc/gcc/c-family/c-common.h
===================================================================
--- gcc.orig/gcc/c-family/c-common.h
+++ gcc/gcc/c-family/c-common.h
@@ -105,6 +105,8 @@ enum rid
   RID_TYPES_COMPATIBLE_P,
   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
   RID_FRACT, RID_ACCUM,
+  RID_LOAD_LANES, RID_STORE_LANES, RID_LOAD_LANE, RID_STORE_LANE,
+  RID_ARRAY_REF,
 
   /* This means to warn that this is a C++ keyword, and then treat it
      as a normal identifier.  */
Index: gcc/gcc/c-parser.c
===================================================================
--- gcc.orig/gcc/c-parser.c
+++ gcc/gcc/c-parser.c
@@ -5955,6 +5955,33 @@ c_parser_alignof_expression (c_parser *p
     }
 }
 
+struct hack_call {
+  struct hack_call *next;
+  tree decl;
+};
+static struct hack_call *load_lanes, *store_lanes;
+
+static tree
+get_lane_function (struct hack_call **ptr, tree type, int code,
+		   const char *name)
+{
+  struct hack_call *call;
+
+  while ((call = *ptr))
+    {
+      if (comptypes (TREE_TYPE (call->decl), type) == 1)
+	return call->decl;
+      ptr = &call->next;
+    }
+  call = XNEW (struct hack_call);
+  call->decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+			   get_identifier (name), type);
+  DECL_BUILT_IN_CLASS (call->decl) = BUILT_IN_NORMAL;
+  DECL_FUNCTION_CODE (call->decl) = (enum built_in_function) code;
+  TREE_READONLY (call->decl) = 1;
+  return call->decl;
+}
+
 /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
 
    postfix-expression:
@@ -6014,6 +6041,7 @@ c_parser_postfix_expression (c_parser *p
 {
   struct c_expr expr, e1, e2, e3;
   struct c_type_name *t1, *t2;
+  int x;
   location_t loc = c_parser_peek_token (parser)->location;;
   expr.original_code = ERROR_MARK;
   expr.original_type = NULL;
@@ -6435,6 +6463,204 @@ c_parser_postfix_expression (c_parser *p
 	    expr.value = objc_build_encode_expr (type);
 	  }
 	  break;
+	case RID_LOAD_LANES:
+	  x = 0;
+	  goto lanes;
+	case RID_STORE_LANES:
+	  x = 1;
+	lanes:
+	  c_parser_consume_token (parser);
+	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	    {
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e1 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e1.value);
+	  e1.value = c_fully_fold (e1.value, false, NULL);
+	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  loc = c_parser_peek_token (parser)->location;
+	  t1 = c_parser_type_name (parser);
+	  if (t1 == NULL)
+	    {
+	      expr.value = error_mark_node;
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      break;
+	    }
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  {
+	    tree decl, rtype, ftype, ctype;
+
+	    rtype = groktypename (t1, NULL, NULL);
+	    ftype = build_function_type_list (rtype, TREE_TYPE (e1.value),
+					      NULL_TREE);
+	    if (x == 0)
+	      decl = get_lane_function (&load_lanes, ftype,
+					BUILT_IN_LOAD_LANES,
+					"__builtin_load_lanes");
+	    else
+	      decl = get_lane_function (&store_lanes, ftype,
+					BUILT_IN_STORE_LANES,
+					"__builtin_store_lanes");
+	    ctype = build_pointer_type (TREE_TYPE (decl));
+	    expr.value = build1 (ADDR_EXPR, ctype, decl);
+	    expr.value = build_call_nary (rtype, expr.value, 1, e1.value);
+	    break;
+	  }
+	case RID_LOAD_LANE:
+	  c_parser_consume_token (parser);
+	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	    {
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e1 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e1.value);
+	  e1.value = c_fully_fold (e1.value, false, NULL);
+	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e2 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e2.value);
+	  e2.value = c_fully_fold (e2.value, false, NULL);
+	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e3 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e3.value);
+	  e3.value = c_fully_fold (e3.value, false, NULL);
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  {
+	    tree decl, rtype, ftype, ctype;
+
+	    rtype = TREE_TYPE (e2.value);
+	    ftype = build_function_type_list (rtype, TREE_TYPE (e1.value),
+					      TREE_TYPE (e2.value),
+					      TREE_TYPE (e3.value),
+					      NULL_TREE);
+	    decl = get_lane_function (&load_lanes, ftype,
+				      BUILT_IN_LOAD_LANE,
+				      "__builtin_load_lane");
+	    ctype = build_pointer_type (TREE_TYPE (decl));
+	    expr.value = build1 (ADDR_EXPR, ctype, decl);
+	    expr.value = build_call_nary (rtype, expr.value, 3, e1.value,
+					  e2.value, e3.value);
+	    break;
+	  }
+	case RID_STORE_LANE:
+	  c_parser_consume_token (parser);
+	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	    {
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e1 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e1.value);
+	  e1.value = c_fully_fold (e1.value, false, NULL);
+	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e2 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e2.value);
+	  e2.value = c_fully_fold (e2.value, false, NULL);
+	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  loc = c_parser_peek_token (parser)->location;
+	  t1 = c_parser_type_name (parser);
+	  if (t1 == NULL)
+	    {
+	      expr.value = error_mark_node;
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      break;
+	    }
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  {
+	    tree decl, rtype, ftype, ctype;
+
+	    rtype = groktypename (t1, NULL, NULL);
+	    ftype = build_function_type_list (rtype, TREE_TYPE (e1.value),
+					      TREE_TYPE (e2.value),
+					      NULL_TREE);
+	    decl = get_lane_function (&load_lanes, ftype,
+				      BUILT_IN_STORE_LANE,
+				      "__builtin_store_lane");
+	    ctype = build_pointer_type (TREE_TYPE (decl));
+	    expr.value = build1 (ADDR_EXPR, ctype, decl);
+	    expr.value = build_call_nary (rtype, expr.value, 2,
+					  e1.value, e2.value);
+	    break;
+	  }
+	case RID_ARRAY_REF:
+	  c_parser_consume_token (parser);
+	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	    {
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e1 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e1.value);
+	  e1.value = c_fully_fold (e1.value, false, NULL);
+	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e2 = c_parser_expr_no_commas (parser, NULL);
+	  mark_exp_read (e2.value);
+	  e2.value = c_fully_fold (e2.value, false, NULL);
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  {
+	    tree ltype, upper;
+	    unsigned int nelems;
+
+	    ltype = TREE_TYPE (e1.value);
+	    if (TREE_CODE (ltype) != POINTER_TYPE)
+	      {
+		error ("first argument to %<__array_ref%> must"
+		       " be a pointer");
+		expr.value = error_mark_node;
+		break;
+	      }
+
+	    if (!host_integerp (e2.value, 1))
+	      {
+		error ("second arguments to %<__array_ref%> must"
+		       " be a constant integer");
+		expr.value = error_mark_node;
+		break;
+	      }
+
+	    nelems = tree_low_cst (e2.value, 1);
+	    upper = build_int_cst (size_type_node, nelems - 1);
+	    ltype = build_array_type (TREE_TYPE (ltype),
+				      build_index_type (upper));
+	    expr.value = convert (build_pointer_type (ltype), e1.value);
+	    expr.value = build1 (INDIRECT_REF, ltype, expr.value);
+	    break;
+	  }
 	default:
 	  c_parser_error (parser, "expected expression");
 	  expr.value = error_mark_node;
