diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y
index 067ad3d8d..e6b1c2fd0 100644
--- a/util/mcgg/gram.y
+++ b/util/mcgg/gram.y
@@ -25,6 +25,7 @@ extern int yylex(void);
     struct constraint* constraint;
 }
 
+%term ALIASES
 %term COPY
 %term CORRUPTED
 %term COST
@@ -43,6 +44,7 @@ extern int yylex(void);
 %token <string>     ID
 %token <string>     QFRAGMENT
 
+%type  <stringlist> aliases;
 %type  <constraint> constraint
 %type  <constraint> constraints
 %type  <expr>       predicate
@@ -72,10 +74,16 @@ registers
 
 register
     : ID QFRAGMENT                    { $$ = makereg($1, $2); }
+    | register ALIASES '(' aliases ')' { $$ = $1; addregaliases($$, $4); }
     | register ID                     { $$ = $1; addregattr($1, $2, false); }
     | register ID '!'                 { $$ = $1; addregattr($1, $2, true); }
     ;
 
+aliases
+    : ID                              { $$ = calloc(1, sizeof(*$$)); stringlist_add($$, $1); }
+    | aliases ',' ID                  { $$ = $1; stringlist_add($$, $3); }
+    ;
+
 declarations
     : /* nothing */
     | declarations declaration ';'
diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c
index 39cdf9729..cf7950b26 100644
--- a/util/mcgg/iburg.c
+++ b/util/mcgg/iburg.c
@@ -279,6 +279,7 @@ struct reg* makereg(const char* id, const char* realname)
 	p->name = id;
 	p->realname = realname;
 	p->number = number++;
+	array_append(&p->aliases, p);
 	smap_put(&registers, id, p);
 
 	return p;
@@ -311,6 +312,34 @@ void addregattr(struct reg* reg, const char* id, bool exact)
 		reg->type |= 1<<(p->number);
 }
 
+void addregalias(struct reg* r1, struct reg* r2)
+{
+	if (!array_appendu(&r1->aliases, r2))
+	{
+		int i;
+
+		for (i=0; i<r1->aliases.count; i++)
+			addregalias(r1->aliases.item[i], r2);
+	}
+}
+
+void addregaliases(struct reg* reg, struct stringlist* aliases)
+{
+	struct stringfragment* f = aliases->first;
+
+	while (f)
+	{
+		struct reg* r = smap_get(&registers, f->data);
+		if (!r)
+			yyerror("register '%s' is not defined here", f->data);
+
+		array_appendu(&reg->aliases, r);
+		array_appendu(&r->aliases, reg);
+
+		f = f->next;
+	}
+}
+
 struct regattr* getregattr(const char* id)
 {
 	struct regattr* p = smap_get(&registerattrs, id);
@@ -588,7 +617,17 @@ static void emitregisterattrs(void)
 
 static void emitregisters(void)
 {
-	int i;
+	int i, j;
+
+	for (i=0; i<registers.count; i++)
+	{
+		struct reg* r = registers.item[i].right;
+
+		print("const struct %Pregister_data* %Pregister_aliases_%d_%s[] = {\n%1", i, r->name);
+		for (j=0; j<r->aliases.count; j++)
+			print("&%Pregister_data[%d], ", r->aliases.item[j]->number);
+		print("NULL\n};\n");
+	}
 
 	print("const struct %Pregister_data %Pregister_data[] = {\n");
 	for (i=0; i<registers.count; i++)
@@ -596,8 +635,8 @@ static void emitregisters(void)
 		struct reg* r = registers.item[i].right;
 		assert(r->number == i);
 
-		print("%1{ \"%s\", \"%s\", 0x%x, 0x%x },\n",
-			r->name, r->realname, r->type, r->attrs);
+		print("%1{ \"%s\", \"%s\", 0x%x, 0x%x, %Pregister_aliases_%d_%s },\n",
+			r->name, r->realname, r->type, r->attrs, i, r->name);
 	}
 	print("%1{ NULL }\n");
 	print("};\n\n");
diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h
index d12985eb6..f50e4c9da 100644
--- a/util/mcgg/iburg.h
+++ b/util/mcgg/iburg.h
@@ -58,11 +58,12 @@ struct terminfo
 
 struct reg
 {
-	const char* name;      /* friendly register name */
-	const char* realname;  /* name used in assembly output */
-	int number;            /* identifying number */
-	uint32_t attrs;        /* bitfield of register attributes */
-	uint32_t type;         /* register type */
+	const char* name;          /* friendly register name */
+	const char* realname;      /* name used in assembly output */
+	int number;                /* identifying number */
+	uint32_t attrs;            /* bitfield of register attributes */
+	uint32_t type;             /* register type */
+	ARRAYOF(struct reg) aliases; /* registers that this one aliases */
 };
 
 struct regattr
@@ -73,6 +74,7 @@ struct regattr
 
 extern struct reg* makereg(const char* name, const char* realname);
 extern void addregattr(struct reg* reg, const char* regattr, bool exact);
+extern void addregaliases(struct reg* reg, struct stringlist* aliases);
 extern struct regattr* getregattr(const char* name);
 
 struct term
diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h
index 2631e0097..211aaf1cc 100644
--- a/util/mcgg/mcgg.h
+++ b/util/mcgg/mcgg.h
@@ -67,6 +67,7 @@ struct burm_register_data
     const char* realname;
     uint32_t type;
     uint32_t attrs;
+    const struct burm_register_data** aliases;
 };
 
 extern const struct burm_register_data burm_register_data[];
diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l
index d26dfac81..44a582456 100644
--- a/util/mcgg/scan.l
+++ b/util/mcgg/scan.l
@@ -39,6 +39,7 @@ static int braces = 0;
 "DECLARATIONS"              return DECLARATIONS;
 "PATTERNS"                  return PATTERNS;
 "REGISTERS"                 return REGISTERS;
+"aliases"                   return ALIASES;
 "corrupted"                 return CORRUPTED;
 "cost"                      return COST;
 "emit"                      return EMIT;