diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index f2436d7..a9188dc 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -12638,7 +12638,50 @@ get_kernel_launch_attributes (gimple_stmt_iterator *gsi, gomp_target *tgt_stmt)
   return build_fold_addr_expr (lattrs);
 }
 
-/* Create an array of arguments that is then passed to GOMP_target.  */
+/* Build target argument identifier from the DEVICE identifier, value
+   identifier ID and whether the element also has a SUBSEQUENT_PARAM.  */
+
+static tree
+get_target_argument_identifier_1 (int device, bool subseqent_param, int id)
+{
+  tree t = build_int_cst (integer_type_node, device);
+  if (subseqent_param)
+    t = fold_build2 (BIT_IOR_EXPR, integer_type_node, t,
+		     build_int_cst (integer_type_node,
+				    GOMP_TARGET_ARG_SUBSEQUENT_PARAM));
+  t = fold_build2 (BIT_IOR_EXPR, integer_type_node, t,
+		   build_int_cst (integer_type_node, id));
+  return t;
+}
+
+/* Like above but return it in type that can be directly stored as an element
+   of the argument array.  */
+
+static tree
+get_target_argument_identifier (int device, bool subseqent_param, int id)
+{
+  tree t = get_target_argument_identifier_1 (device, subseqent_param, id);
+  return fold_convert (ptr_type_node, t);
+}
+
+/* Return a target argument consisiting of DEVICE identifier, value identifier
+   ID, and the actual VALUE.  */
+
+static tree
+get_target_argument_value (gimple_stmt_iterator *gsi, int device, int id,
+			   tree value)
+{
+  tree t = fold_build2 (LSHIFT_EXPR, integer_type_node,
+			fold_convert (integer_type_node, value),
+			build_int_cst (unsigned_type_node,
+				       GOMP_TARGET_ARG_VALUE_SHIFT));
+  t = fold_build2 (BIT_IOR_EXPR, integer_type_node, t,
+		   get_target_argument_identifier_1 (device, false, id));
+  t = fold_convert (ptr_type_node, t);
+  return force_gimple_operand_gsi (gsi, t, true, NULL, true, GSI_SAME_STMT);
+}
+
+/* Create an array of arguments that is then passed to GOMP_target.   */
 
 static tree
 get_target_arguments (gimple_stmt_iterator *gsi, gomp_target *tgt_stmt)
@@ -12647,28 +12690,28 @@ get_target_arguments (gimple_stmt_iterator *gsi, gomp_target *tgt_stmt)
   tree clauses = gimple_omp_target_clauses (tgt_stmt);
   tree t, c = find_omp_clause (clauses, OMP_CLAUSE_NUM_TEAMS);
   if (c)
-    {
-      t = fold_convert (ptr_type_node, OMP_CLAUSE_NUM_TEAMS_EXPR (c));
-      t = force_gimple_operand_gsi (gsi, t, true, NULL, true, GSI_SAME_STMT);
-    }
+    t = OMP_CLAUSE_NUM_TEAMS_EXPR (c);
   else
-    t = fold_convert (ptr_type_node, integer_minus_one_node);
+    t = integer_minus_one_node;
+  t = get_target_argument_value (gsi, GOMP_TARGET_ARG_DEVICE_ALL,
+				 GOMP_TARGET_ARG_NUM_TEAMS, t);
   args.quick_push (t);
+
   c = find_omp_clause (clauses, OMP_CLAUSE_THREAD_LIMIT);
   if (c)
-    {
-      t = fold_convert (ptr_type_node, OMP_CLAUSE_THREAD_LIMIT_EXPR (c));
-      t = force_gimple_operand_gsi (gsi, t, true, NULL, true, GSI_SAME_STMT);
-    }
+    t = OMP_CLAUSE_THREAD_LIMIT_EXPR (c);
   else
-    t = fold_convert (ptr_type_node, integer_minus_one_node);
+    t = integer_minus_one_node;
+  t = get_target_argument_value (gsi, GOMP_TARGET_ARG_DEVICE_ALL,
+				 GOMP_TARGET_ARG_THREAD_LIMIT, t);
   args.quick_push (t);
 
   /* Add HSA-specific grid sizes, if available.  */
   if (gimple_omp_target_dimensions (tgt_stmt))
     {
-      args.quick_push (build_int_cst (ptr_type_node,
-				     GOMP_TARGET_ARG_HSA_KERNEL_ATTRIBUTES));
+      t = get_target_argument_identifier (GOMP_DEVICE_HSA, true,
+					  GOMP_TARGET_ARG_HSA_KERNEL_ATTRIBUTES);
+      args.quick_push (t);
       args.quick_push (get_kernel_launch_attributes (gsi, tgt_stmt));
     }
 
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 9a792e0..747e7b0 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -229,18 +229,32 @@ enum gomp_map_kind
 #define GOMP_LAUNCH_OP(X) (((X) >> GOMP_LAUNCH_OP_SHIFT) & 0xffff)
 #define GOMP_LAUNCH_OP_MAX 0xffff
 
-/* First device-specific identifier among target arguments. */
-#define GOMP_TARGET_ARG_FIRST_DEVICE_SPECIFIC	2
-/* Target argument index of NUM_TEAMS */
-#define GOMP_TARGET_ARG_NUM_TEAMS		0
-/* Target argument index of THREAD_LIMIT */
-#define GOMP_TARGET_ARG_THREAD_LIMIT		1
-
-/* Identifiers of device-specific target arguments.  */
-#define GOMP_TARGET_ARG_HSA_KERNEL_ATTRIBUTES	1
+/* Bitmask to apply in order to find out the intended device of a target
+   argument.  */
+#define GOMP_TARGET_ARG_DEVICE_MASK		((1 << 7) - 1)
+/* The target argument is significant for all devices.  */
+#define GOMP_TARGET_ARG_DEVICE_ALL		0
+
+/* Flag set when the subsequent element in the device-specific argument
+   values.  */
+#define GOMP_TARGET_ARG_SUBSEQUENT_PARAM	(1 << 7)
+
+/* Bitmask to apply to a target argument to find out the value identifier.  */
+#define GOMP_TARGET_ARG_ID_MASK			(((1 << 8) - 1) << 8)
+/* Target argument index of NUM_TEAMS.  */
+#define GOMP_TARGET_ARG_NUM_TEAMS		(1 << 8)
+/* Target argument index of THREAD_LIMIT.  */
+#define GOMP_TARGET_ARG_THREAD_LIMIT		(2 << 8)
+
+/* If the value is directly embeded in target argument, it should be a 16-bit
+   at most and shifted by tis many bits.  */
+#define GOMP_TARGET_ARG_VALUE_SHIFT		16
 
 /* HSA specific data structures.  */
 
+/* Identifiers of device-specific target arguments.  */
+#define GOMP_TARGET_ARG_HSA_KERNEL_ATTRIBUTES	(1 << 8)
+
 /* Structure describing the run-time and grid properties of an HSA kernel
    lauch.  */
 
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index 72f5bdd..f0e7044 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -1047,12 +1047,12 @@ init_kernel (struct kernel_info *kernel)
 		       "mutex");
 }
 
-/* Parse the launch attributes INPUT provided by the compiler and return true
+/* Parse the target attributes INPUT provided by the compiler and return true
    if we should run anything all.  If INPUT is NULL, fill DEF with default
    values, then store INPUT or DEF into *RESULT.  */
 
 static bool
-parse_launch_attributes (void **input,
+parse_target_attributes (void **input,
 			 struct GOMP_kernel_launch_attributes *def,
 			 struct GOMP_kernel_launch_attributes **result)
 {
@@ -1060,16 +1060,20 @@ parse_launch_attributes (void **input,
     GOMP_PLUGIN_fatal ("No target arguments provided");
 
   bool attrs_found = false;
-  input += GOMP_TARGET_ARG_FIRST_DEVICE_SPECIFIC;
   while (*input)
     {
       uintptr_t id = (uintptr_t) *input;
-      input++;
-      if (id == GOMP_TARGET_ARG_HSA_KERNEL_ATTRIBUTES)
+      if ((id & GOMP_TARGET_ARG_DEVICE_MASK) == GOMP_DEVICE_HSA
+	  && ((id & GOMP_TARGET_ARG_ID_MASK)
+	      == GOMP_TARGET_ARG_HSA_KERNEL_ATTRIBUTES))
 	{
+	  input++;
 	  attrs_found = true;
 	  break;
 	}
+
+      if (id & GOMP_TARGET_ARG_SUBSEQUENT_PARAM)
+	input++;
       input++;
     }
 
@@ -1138,7 +1142,7 @@ GOMP_OFFLOAD_run (int n, void *fn_ptr, void *vars, void** args)
   struct agent_info *agent = kernel->agent;
   struct GOMP_kernel_launch_attributes def;
   struct GOMP_kernel_launch_attributes *kla;
-  if (!parse_launch_attributes (args, &def, &kla))
+  if (!parse_target_attributes (args, &def, &kla))
     {
       HSA_DEBUG ("Will not run HSA kernel because the grid size is zero\n");
       return;
