diff --git a/gcc/config/nvptx/nvptx-protos.h b/gcc/config/nvptx/nvptx-protos.h
index 0bf9af406a22d73ee16eab40218cd15b162d5aa9..ca0a87ee4bd68a4e2928cd0d49d2a02f37aa2e60 100644
--- a/gcc/config/nvptx/nvptx-protos.h
+++ b/gcc/config/nvptx/nvptx-protos.h
@@ -43,6 +43,7 @@ extern void nvptx_output_ascii (FILE *, const char *, unsigned HOST_WIDE_INT);
 extern void nvptx_cpu_cpp_builtins (void);
 extern void nvptx_register_pragmas (void);
 extern unsigned int nvptx_data_alignment (const_tree, unsigned int);
+extern void nvptx_asm_output_def_from_decls (FILE *, tree, tree);
 
 #ifdef RTX_CODE
 extern void nvptx_expand_oacc_fork (unsigned);
diff --git a/gcc/config/nvptx/nvptx.cc b/gcc/config/nvptx/nvptx.cc
index f83f98c3ab5945c5036a92173ef112a33ef2b811..b2f7b4af392d401300e69a243cf7ec859daafa2b 100644
--- a/gcc/config/nvptx/nvptx.cc
+++ b/gcc/config/nvptx/nvptx.cc
@@ -77,6 +77,7 @@
 #include "opts.h"
 #include "tree-pretty-print.h"
 #include "rtl-iter.h"
+#include "cgraph.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -968,7 +969,8 @@ static void
 write_fn_proto_1 (std::stringstream &s, bool is_defn,
 		  const char *name, const_tree decl)
 {
-  write_fn_marker (s, is_defn, TREE_PUBLIC (decl), name);
+  if (lookup_attribute ("alias", DECL_ATTRIBUTES (decl)) == NULL)
+    write_fn_marker (s, is_defn, TREE_PUBLIC (decl), name);
 
   /* PTX declaration.  */
   if (DECL_EXTERNAL (decl))
@@ -7393,6 +7395,76 @@ nvptx_mem_local_p (rtx mem)
   return false;
 }
 
+/* Define locally, for use in NVPTX_ASM_OUTPUT_DEF.  */
+#define SET_ASM_OP ".alias "
+
+/* Define locally, for use in nvptx_asm_output_def_from_decls.  Add NVPTX_
+   prefix to avoid clash with ASM_OUTPUT_DEF from nvptx.h.
+   Copy of ASM_OUTPUT_DEF from defaults.h, with added terminating
+   semicolon.  */
+#define NVPTX_ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2)	\
+  do							\
+    {							\
+      fprintf ((FILE), "%s", SET_ASM_OP);		\
+      assemble_name (FILE, LABEL1);			\
+      fprintf (FILE, ",");				\
+      assemble_name (FILE, LABEL2);			\
+      fprintf (FILE, ";\n");				\
+    }							\
+  while (0)
+
+void
+nvptx_asm_output_def_from_decls (FILE *stream, tree name, tree value)
+{
+  if (nvptx_alias == 0 || !TARGET_PTX_6_3)
+    {
+      /* Copied from assemble_alias.  */
+      error_at (DECL_SOURCE_LOCATION (name),
+		"alias definitions not supported in this configuration");
+      TREE_ASM_WRITTEN (name) = 1;
+      return;
+    }
+
+  if (lookup_attribute ("weak", DECL_ATTRIBUTES (name)))
+    {
+      /* Prevent execution FAILs for gcc.dg/globalalias.c and
+	 gcc.dg/pr77587.c.  */
+      error_at (DECL_SOURCE_LOCATION (name),
+		"weak alias definitions not supported in this configuration");
+      TREE_ASM_WRITTEN (name) = 1;
+      return;
+    }
+
+  /* Ptx also doesn't support value having weak linkage, but we can't detect
+     that here, so we'll end up with:
+     "error: Function test with .weak scope cannot be aliased".
+     See gcc.dg/localalias.c.  */
+
+  if (TREE_CODE (name) != FUNCTION_DECL)
+    {
+      error_at (DECL_SOURCE_LOCATION (name),
+		"non-function alias definitions not supported"
+		" in this configuration");
+      TREE_ASM_WRITTEN (name) = 1;
+      return;
+    }
+
+  if (!cgraph_node::get (name)->referred_to_p ())
+    /* Prevent "Internal error: reference to deleted section".  */
+    return;
+
+  std::stringstream s;
+  write_fn_proto (s, false, get_fnname_from_decl (name), name);
+  fputs (s.str ().c_str (), stream);
+
+  tree id = DECL_ASSEMBLER_NAME (name);
+  NVPTX_ASM_OUTPUT_DEF (stream, IDENTIFIER_POINTER (id),
+			IDENTIFIER_POINTER (value));
+}
+
+#undef NVPTX_ASM_OUTPUT_DEF
+#undef SET_ASM_OP
+
 #undef TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE nvptx_option_override
 
diff --git a/gcc/config/nvptx/nvptx.h b/gcc/config/nvptx/nvptx.h
index b55ade65cc580353ec19431754eb131c6ce7069a..75ac7a666b1391bb5b443e171c3876e31af2b0f1 100644
--- a/gcc/config/nvptx/nvptx.h
+++ b/gcc/config/nvptx/nvptx.h
@@ -315,6 +315,23 @@ struct GTY(()) machine_function
   ((VALUE) = GET_MODE_BITSIZE ((MODE)), 2)
 
 #define SUPPORTS_WEAK 1
+
+/* The documentation states that ASM_OUTPUT_DEF_FROM_DECLS is used in
+   preference to ASM_OUTPUT_DEF if the tree nodes are available.  However, we
+   need the tree nodes to emit the prototype, so at this point it's not clear
+   how we can support ASM_OUTPUT_DEF.  Still, we need to define it, or
+   ASM_OUTPUT_DEF_FROM_DECLS is ignored.  For now, assert, and once we run
+   into it possibly improve by somehow emitting the prototype elsewhere, or
+   emitting a reasonable error message.  */
+#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2)	\
+  do						\
+    {						\
+      gcc_unreachable ();			\
+    }						\
+  while (0)
+#define ASM_OUTPUT_DEF_FROM_DECLS(STREAM, NAME, VALUE)	\
+  nvptx_asm_output_def_from_decls (STREAM, NAME, VALUE)
+
 #define NO_DOT_IN_LABEL
 #define ASM_COMMENT_START "//"
 
diff --git a/gcc/config/nvptx/nvptx.opt b/gcc/config/nvptx/nvptx.opt
index fea99c5d4069e5f8e23b1144402431ea54cc56a4..980428b58cc80d27c194a996e4add9d495115979 100644
--- a/gcc/config/nvptx/nvptx.opt
+++ b/gcc/config/nvptx/nvptx.opt
@@ -85,3 +85,6 @@ Initialize ptx registers.
 
 mptx-comment
 Target Var(nvptx_comment) Init(1) Undocumented
+
+malias
+Target Var(nvptx_alias) Init(0) Undocumented
diff --git a/gcc/testsuite/gcc.target/nvptx/alias-1.c b/gcc/testsuite/gcc.target/nvptx/alias-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..f68716e77dd6dc346f012b819cf24bbc23db984e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nvptx/alias-1.c
@@ -0,0 +1,27 @@
+/* { dg-do link } */
+/* { dg-do run { target runtime_ptx_isa_version_6_3 } } */
+/* { dg-options "-save-temps -malias -mptx=6.3" } */
+
+int v;
+
+void __f ()
+{
+  v = 1;
+}
+
+void f () __attribute__ ((alias ("__f")));
+
+int
+main (void)
+{
+  if (v != 0)
+    __builtin_abort ();
+  f ();
+  if (v != 1)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "\\.alias f,__f;" 1 } } */
+/* { dg-final { scan-assembler-times "\\.visible \\.func __f;" 1 } } */
+/* { dg-final { scan-assembler-times "\\.visible \\.func f;" 1 } } */
diff --git a/gcc/testsuite/gcc.target/nvptx/alias-2.c b/gcc/testsuite/gcc.target/nvptx/alias-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..e2dc9b1f5aca472a6ba0a2192a82a1a5c93aa203
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nvptx/alias-2.c
@@ -0,0 +1,13 @@
+/* { dg-do link } */
+/* { dg-do run { target runtime_ptx_isa_version_6_3 } } */
+/* { dg-options "-save-temps -malias -mptx=6.3 -O2" } */
+
+#include "alias-1.c"
+
+/* Inlined, so no alias.  */
+/* { dg-final { scan-assembler-not "\\.alias.*;" } } */
+/* { dg-final { scan-assembler-not "\\.visible \\.func f;" } } */
+
+/* Note static and inlined, so still there.  */
+/* { dg-final { scan-assembler-times "\\.visible \\.func __f;" 1 } } */
+
diff --git a/gcc/testsuite/gcc.target/nvptx/alias-3.c b/gcc/testsuite/gcc.target/nvptx/alias-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..60486e508269665e63848d0ccb47fb32ae75088a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nvptx/alias-3.c
@@ -0,0 +1,29 @@
+/* { dg-do link } */
+/* { dg-do run { target runtime_ptx_isa_version_6_3 } } */
+/* { dg-options "-save-temps -malias -mptx=6.3" } */
+
+/* Copy of alias-1.c, with static __f and f.  */
+
+int v;
+
+static void __f ()
+{
+  v = 1;
+}
+
+static void f () __attribute__ ((alias ("__f")));
+
+int
+main (void)
+{
+  if (v != 0)
+    __builtin_abort ();
+  f ();
+  if (v != 1)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-assembler-times "\\.alias f,__f;" 1 } } */
+/* { dg-final { scan-assembler-times "\\.func __f;" 1 } } */
+/* { dg-final { scan-assembler-times "\\.func f;" 1 } } */
diff --git a/gcc/testsuite/gcc.target/nvptx/alias-4.c b/gcc/testsuite/gcc.target/nvptx/alias-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..956150a6b3f74cc7df69b365415710d2fa518a2c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nvptx/alias-4.c
@@ -0,0 +1,12 @@
+/* { dg-do link } */
+/* { dg-do run { target runtime_ptx_isa_version_6_3 } } */
+/* { dg-options "-save-temps -malias -mptx=6.3 -O2" } */
+
+#include "alias-3.c"
+
+/* Inlined, so no alias.  */
+/* { dg-final { scan-assembler-not "\\.alias.*;" } } */
+/* { dg-final { scan-assembler-not "\\.func f;" } } */
+
+/* Static and inlined, so it's deleted.  */
+/* { dg-final { scan-assembler-not "\\.func __f;" } } */
diff --git a/gcc/testsuite/gcc.target/nvptx/nvptx.exp b/gcc/testsuite/gcc.target/nvptx/nvptx.exp
index 284ba41908e029856dda50a4b57d531a8c788c90..e69b6d35feda7a42818e2300daee8a7ce8e63873 100644
--- a/gcc/testsuite/gcc.target/nvptx/nvptx.exp
+++ b/gcc/testsuite/gcc.target/nvptx/nvptx.exp
@@ -25,6 +25,13 @@ if ![istarget nvptx*-*-*] then {
 # Load support procs.
 load_lib gcc-dg.exp
 
+# Return 1 if code with -mptx=6.3 can be run.
+proc check_effective_target_runtime_ptx_isa_version_6_3 { args } {
+    return [check_runtime run_ptx_isa_6_3 {
+	int main (void) { return 0; }
+    } "-mptx=6.3"]
+}
+
 # If a testcase doesn't have special options, use these.
 global DEFAULT_CFLAGS
 if ![info exists DEFAULT_CFLAGS] then {