Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
+++ src/SymTab/Mangler.cc	(revision 642bc8337f1daad8ffe4937360de682bc679d6fe)
@@ -73,4 +73,5 @@
 				bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
 				bool inFunctionType = false;    ///< Include type qualifiers if false.
+				bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
 
 				void mangleDecl( DeclarationWithType *declaration );
@@ -110,12 +111,11 @@
 					isTopLevel = false;
 				} // if
-				mangleName << "__";
+				mangleName << Encoding::manglePrefix;
 				CodeGen::OperatorInfo opInfo;
 				if ( operatorLookup( declaration->get_name(), opInfo ) ) {
-					mangleName << opInfo.outputName;
+					mangleName << opInfo.outputName.size() << opInfo.outputName;
 				} else {
-					mangleName << declaration->get_name();
-				} // if
-				mangleName << nameSeparator;
+					mangleName << declaration->name.size() << declaration->name;
+				} // if
 				maybeAccept( declaration->get_type(), *visitor );
 				if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
@@ -123,7 +123,7 @@
 					// so they need a different name mangling
 					if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
-						mangleName << "autogen__";
+						mangleName << Encoding::autogen;
 					} else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
-						mangleName << "intrinsic__";
+						mangleName << Encoding::intrinsic;
 					} else {
 						// if we add another kind of overridable function, this has to change
@@ -144,11 +144,11 @@
 			void Mangler::postvisit( VoidType * voidType ) {
 				printQualifiers( voidType );
-				mangleName << "v";
+				mangleName << Encoding::voidType;
 			}
 
 			void Mangler::postvisit( BasicType * basicType ) {
 				printQualifiers( basicType );
-				assert( basicType->get_kind() < numBtLetter );
-				mangleName << btLetter[ basicType->get_kind() ];
+				assert( basicType->get_kind() < BasicType::NUMBER_OF_BASIC_TYPES );
+				mangleName << Encoding::basicTypes[ basicType->get_kind() ];
 			}
 
@@ -156,5 +156,5 @@
 				printQualifiers( pointerType );
 				// mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers
-				if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName << "P";
+				if ( ! dynamic_cast<FunctionType *>( pointerType->base ) ) mangleName << Encoding::pointer;
 				maybeAccept( pointerType->base, *visitor );
 			}
@@ -163,5 +163,5 @@
 				// TODO: encode dimension
 				printQualifiers( arrayType );
-				mangleName << "A0";
+				mangleName << Encoding::array << "0";
 				maybeAccept( arrayType->base, *visitor );
 			}
@@ -188,5 +188,5 @@
 			void Mangler::postvisit( FunctionType * functionType ) {
 				printQualifiers( functionType );
-				mangleName << "F";
+				mangleName << Encoding::function;
 				// turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
 				// since qualifiers on outermost parameter type do not differentiate function types, e.g.,
@@ -195,5 +195,5 @@
 				inFunctionType = true;
 				std::list< Type* > returnTypes = getTypes( functionType->returnVals );
-				if (returnTypes.empty()) mangleName << "v";
+				if (returnTypes.empty()) mangleName << Encoding::voidType;
 				else acceptAll( returnTypes, *visitor );
 				mangleName << "_";
@@ -206,5 +206,5 @@
 				printQualifiers( refType );
 
-				mangleName << ( refType->name.length() + prefix.length() ) << prefix << refType->name;
+				mangleName << prefix << refType->name.length() << refType->name;
 
 				if ( mangleGenericParams ) {
@@ -261,31 +261,41 @@
 			void Mangler::postvisit( TraitInstType * inst ) {
 				printQualifiers( inst );
-				mangleName << "_Y" << inst->name << "_";
+				mangleName << inst->name.size() << inst->name;
 			}
 
 			void Mangler::postvisit( TupleType * tupleType ) {
 				printQualifiers( tupleType );
-				mangleName << "T";
+				mangleName << Encoding::tuple << tupleType->types.size();
 				acceptAll( tupleType->types, *visitor );
-				mangleName << "_";
 			}
 
 			void Mangler::postvisit( VarArgsType * varArgsType ) {
 				printQualifiers( varArgsType );
-				mangleName << "VARGS";
+				static const std::string vargs = "__builtin_va_list";
+				mangleName << vargs.size() << vargs;
 			}
 
 			void Mangler::postvisit( ZeroType * ) {
-				mangleName << "Z";
+				mangleName << Encoding::zero;
 			}
 
 			void Mangler::postvisit( OneType * ) {
-				mangleName << "O";
+				mangleName << Encoding::one;
 			}
 
 			void Mangler::postvisit( QualifiedType * qualType ) {
+				bool inqual = inQualifiedType;
+				if (! inqual ) {
+					// N marks the start of a qualified type
+					inQualifiedType = true;
+					mangleName << Encoding::qualifiedTypeStart;
+				}
 				maybeAccept( qualType->parent, *visitor );
-				mangleName << "__";
 				maybeAccept( qualType->child, *visitor );
+				if ( ! inqual ) {
+					// E marks the end of a qualified type
+					inQualifiedType = false;
+					mangleName << Encoding::qualifiedTypeEnd;
+				}
 			}
 
@@ -339,8 +349,8 @@
 					// these qualifiers do not distinguish the outermost type of a function parameter
 					if ( type->get_const() ) {
-						mangleName << "C";
+						mangleName << Encoding::qualifiers.at(Type::Const);
 					} // if
 					if ( type->get_volatile() ) {
-						mangleName << "V";
+						mangleName << Encoding::qualifiers.at(Type::Volatile);
 					} // if
 					// Removed due to restrict not affecting function compatibility in GCC
@@ -349,13 +359,13 @@
 					// } // if
 					if ( type->get_atomic() ) {
-						mangleName << "A";
+						mangleName << Encoding::qualifiers.at(Type::Atomic);
 					} // if
 				}
 				if ( type->get_mutex() ) {
-					mangleName << "M";
+					mangleName << Encoding::qualifiers.at(Type::Mutex);
 				} // if
 				if ( type->get_lvalue() ) {
 					// mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
-					mangleName << "L";
+					mangleName << Encoding::qualifiers.at(Type::Lvalue);
 				}
 
Index: src/SymTab/Mangler.h
===================================================================
--- src/SymTab/Mangler.h	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
+++ src/SymTab/Mangler.h	(revision 642bc8337f1daad8ffe4937360de682bc679d6fe)
@@ -24,4 +24,11 @@
 #include "SynTree/Visitor.h"  // for Visitor, maybeAccept
 
+// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
+// The CFA name mangling scheme is based closely on the itanium C++ name mangling scheme, with the following key differences:
+// * Variable names are also mangled to include type information, not just functions
+// * CFA does not have template expansion, so the rules for function specialization do not apply.
+// * CFA instead has to handle type parameters and assertion parameters.
+// * Currently name compression is not implemented.
+
 namespace SymTab {
 	namespace Mangler {
@@ -34,8 +41,23 @@
 		std::string mangleConcrete( Type* ty );
 
-		extern const char *btLetter[];
-		extern const int numBtLetter;
-		extern const std::map<int, const char *> qualifierLetter;
-		extern const std::string nameSeparator;
+		namespace Encoding {
+			extern const std::string manglePrefix;
+			extern const std::string basicTypes[];
+			extern const std::map<int, std::string> qualifiers;
+
+			extern const std::string voidType;
+			extern const std::string zero;
+			extern const std::string one;
+
+			extern const std::string function;
+			extern const std::string tuple;
+			extern const std::string pointer;
+			extern const std::string array;
+			extern const std::string qualifiedTypeStart;
+			extern const std::string qualifiedTypeEnd;
+
+			extern const std::string autogen;
+			extern const std::string intrinsic;
+		};
 	} // Mangler
 } // SymTab
Index: src/SymTab/ManglerCommon.cc
===================================================================
--- src/SymTab/ManglerCommon.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
+++ src/SymTab/ManglerCommon.cc	(revision 642bc8337f1daad8ffe4937360de682bc679d6fe)
@@ -19,46 +19,70 @@
 namespace SymTab {
 	namespace Mangler {
-		const char * btLetter[] = {
-			"b",  // Bool
-			"c",  // Char
-			"Sc", // SignedChar
-			"Uc", // UnsignedChar
-			"s",  // ShortSignedInt
-			"Us", // ShortUnsignedInt
-			"i",  // SignedInt
-			"Ui", // UnsignedInt
-			"l",  // LongSignedInt
-			"Ul", // LongUnsignedInt
-			"q",  // LongLongSignedInt
-			"Uq", // LongLongUnsignedInt
-			"f",  // Float
-			"d",  // Double
-			"r",  // LongDouble
-			"Xf", // FloatComplex
-			"Xd", // DoubleComplex
-			"Xr", // LongDoubleComplex
-			"If", // FloatImaginary
-			"Id", // DoubleImaginary
-			"Ir", // LongDoubleImaginary
-			"w",  // SignedInt128
-			"Uw", // UnsignedInt128
-			"x",  // Float80
-			"y",  // Float128
-		};
-		const int numBtLetter = sizeof(btLetter)/sizeof(btLetter[0]);
-		static_assert(
-			numBtLetter == BasicType::NUMBER_OF_BASIC_TYPES,
-			"Each basic type kind should have a corresponding mangler letter"
-		);
+		namespace Encoding {
+			const std::string manglePrefix = "_X";
 
-		const std::map<int, const char *> qualifierLetter = {
-			{ Type::Const, "C" },
-			{ Type::Volatile, "V" },
-			{ Type::Atomic, "A" }, // A = Atomic, A0 = Array and forall parameter...
-			{ Type::Mutex, "M" },
-			{ Type::Lvalue, "L" },
-		};
+			const std::string basicTypes[] = {
+				"b",  // Bool
+				"c",  // Char
+				"a",  // SignedChar
+				"h",  // UnsignedChar
+				"s",  // ShortSignedInt
+				"t",  // ShortUnsignedInt
+				"i",  // SignedInt
+				"j",  // UnsignedInt
+				"l",  // LongSignedInt
+				"m",  // LongUnsignedInt
+				"x",  // LongLongSignedInt
+				"y",  // LongLongUnsignedInt
+				"f",  // Float
+				"d",  // Double
+				"e",  // LongDouble
+				"Cf", // FloatComplex
+				"Cd", // DoubleComplex
+				"Ce", // LongDoubleComplex
+				// Note: imaginary is not an overloadable type in C++
+				"If", // FloatImaginary
+				"Id", // DoubleImaginary
+				"Ie", // LongDoubleImaginary
+				"n",  // SignedInt128
+				"o",  // UnsignedInt128
+				"Dq",  // Float80 -- TODO: itanium says Float80 and LongDouble both encode to "e", but doing this causes problems with constructing long double, because the cost tables are incorrect
+				"g",  // Float128
+				// "z",	// ellipsis
+				// "Dd" // # IEEE 754r decimal floating point (64 bits)
+				// "De" // # IEEE 754r decimal floating point (128 bits)
+				// "Df" // # IEEE 754r decimal floating point (32 bits)
+				// "Dh" // # IEEE 754r half-precision floating point (16 bits)
+				// "DF"N_ // # ISO/IEC TS 18661 binary floating point type _FloatN (N bits)
+				// "Di" // char32_t
+				// "Ds" // char16_t
+			};
+			static_assert(
+				sizeof(basicTypes)/sizeof(basicTypes[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
+				"Each basic type kind should have a corresponding mangler letter"
+			);
 
-		const std::string nameSeparator = "__cfa__";
+			const std::map<int, std::string> qualifiers = {
+				{ Type::Const, "C" },
+				{ Type::Volatile, "V" },
+				{ Type::Atomic, "A" }, // A = Atomic, A0 = Array and forall parameter...
+				{ Type::Mutex, "M" },
+				{ Type::Lvalue, "L" },
+			};
+
+			const std::string voidType = "v";
+			const std::string zero = "Z";
+			const std::string one = "O";
+
+			const std::string function = "F";
+			const std::string tuple = "T";
+			const std::string pointer = "P";
+			const std::string array = "A";
+			const std::string qualifiedTypeStart = "N";
+			const std::string qualifiedTypeEnd = "E";
+
+			const std::string autogen = "autogen__";
+			const std::string intrinsic = "intrinsic__";
+		} // namespace Encoding
 	} // namespace Mangler
 } // namespace SymTab
