Index: src/SymTab/Demangle.cc
===================================================================
--- src/SymTab/Demangle.cc	(revision 4084928eae5498efed55486197c04b51fe7be79b)
+++ src/SymTab/Demangle.cc	(revision 4084928eae5498efed55486197c04b51fe7be79b)
@@ -0,0 +1,529 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Demangler.cc --
+//
+// Author           : Rob Schluntz
+// Created On       : Thu Jul 19 12:52:41 2018
+// Last Modified By : Rob Schluntz
+// Last Modified On : Thu Jul 19 12:54:35 2018
+// Update Count     : 2
+//
+
+#include <algorithm>
+#include <sstream>
+
+#include "CodeGen/GenType.h"
+#include "Common/PassVisitor.h"
+#include "Mangler.h"
+#include "SynTree/Type.h"
+#include "SynTree/Declaration.h"
+
+// #define DEBUG
+#ifdef DEBUG
+#define PRINT(x) x
+#else
+#define PRINT(x) {}
+#endif
+
+namespace {
+	struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
+		std::string typeString;
+		GenType( const std::string &typeString );
+
+		void previsit( BaseSyntaxNode * );
+		void postvisit( BaseSyntaxNode * );
+
+		void postvisit( FunctionType * funcType );
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( ReferenceType * refType );
+		void postvisit( StructInstType * structInst );
+		void postvisit( UnionInstType * unionInst );
+		void postvisit( EnumInstType * enumInst );
+		void postvisit( TypeInstType * typeInst );
+		void postvisit( TupleType  * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
+		void postvisit( GlobalScopeType * globalType );
+		void postvisit( QualifiedType * qualType );
+
+	  private:
+		void handleQualifiers( Type *type );
+		std::string handleGeneric( ReferenceToType * refType );
+		void genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic );
+	};
+
+  std::string genDemangleType( Type * type, const std::string & baseString ) {
+		PassVisitor<GenType> gt( baseString );
+		assert( type );
+		type->accept( gt );
+		return gt.pass.typeString;
+  }
+
+	GenType::GenType( const std::string &typeString ) : typeString( typeString ) {}
+
+	// *** BaseSyntaxNode
+	void GenType::previsit( BaseSyntaxNode * ) {
+		// turn off automatic recursion for all nodes, to allow each visitor to
+		// precisely control the order in which its children are visited.
+		visit_children = false;
+	}
+
+	void GenType::postvisit( BaseSyntaxNode * node ) {
+		std::stringstream ss;
+		node->print( ss );
+		assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
+	}
+
+	void GenType::postvisit( VoidType * voidType ) {
+		typeString = "void " + typeString;
+		handleQualifiers( voidType );
+	}
+
+	void GenType::postvisit( BasicType * basicType ) {
+		BasicType::Kind kind = basicType->kind;
+		assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
+		typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
+		handleQualifiers( basicType );
+	}
+
+	void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool ) {
+		std::ostringstream os;
+		if ( typeString != "" ) {
+			if ( typeString[ 0 ] == '*' ) {
+				os << "(" << typeString << ")";
+			} else {
+				os << typeString;
+			} // if
+		} // if
+		os << "[";
+
+		if ( qualifiers.is_const ) {
+			os << "const ";
+		} // if
+		if ( qualifiers.is_volatile ) {
+			os << "volatile ";
+		} // if
+		if ( qualifiers.is_restrict ) {
+			os << "__restrict ";
+		} // if
+		if ( qualifiers.is_atomic ) {
+			os << "_Atomic ";
+		} // if
+		if ( dimension != 0 ) {
+			// TODO: ???
+			// PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
+			// dimension->accept( cg );
+		} else if ( isVarLen ) {
+			// no dimension expression on a VLA means it came in with the * token
+			os << "*";
+		} // if
+		os << "]";
+
+		typeString = os.str();
+
+		base->accept( *visitor );
+	}
+
+	void GenType::postvisit( PointerType * pointerType ) {
+		assert( pointerType->base != 0);
+		if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
+			assert(false);
+			genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
+		} else {
+			handleQualifiers( pointerType );
+			if ( typeString[ 0 ] == '?' ) {
+				typeString = "* " + typeString;
+			} else {
+				typeString = "*" + typeString;
+			} // if
+			pointerType->base->accept( *visitor );
+		} // if
+	}
+
+	void GenType::postvisit( ArrayType * arrayType ) {
+		genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
+	}
+
+	void GenType::postvisit( ReferenceType * refType ) {
+		assert( false );
+		assert( refType->base != 0);
+		handleQualifiers( refType );
+		typeString = "&" + typeString;
+		refType->base->accept( *visitor );
+	}
+
+	void GenType::postvisit( FunctionType * funcType ) {
+		std::ostringstream os;
+
+		if ( typeString != "" ) {
+			if ( typeString[0] == '*' ) {
+				os << "(" << typeString << ")";
+			} else {
+				os << typeString;
+			} // if
+		} // if
+
+		/************* parameters ***************/
+		const std::list<DeclarationWithType *> &pars = funcType->parameters;
+
+		if ( pars.empty() ) {
+			if ( funcType->get_isVarArgs() ) {
+				os << "()";
+			} else {
+				os << "(void)";
+			} // if
+		} else {
+			os << "(" ;
+
+			unsigned int i = 0;
+			for (DeclarationWithType * p : pars) {
+				os << genDemangleType( p->get_type(), "" );
+				if (++i != pars.size()) os << ", ";
+			}
+
+			if ( funcType->get_isVarArgs() ) {
+				os << ", ...";
+			} // if
+			os << ")";
+		} // if
+
+		typeString = os.str();
+
+		if ( funcType->returnVals.size() == 0 ) {
+			typeString += ": void";
+		} else {
+			typeString += ": " + genDemangleType(funcType->returnVals.front()->get_type(), "");
+		} // if
+
+		// add forall
+		if( ! funcType->forall.empty() ) {
+			std::ostringstream os;
+			os << "forall(";
+			unsigned int i = 0;
+			for ( auto td : funcType->forall ) {
+				os << td->typeString() << " " << td->name;
+				if (! td->assertions.empty()) {
+					os << " | { ";
+					unsigned int j = 0;
+					for (DeclarationWithType * assert : td->assertions) {
+						os << genDemangleType(assert->get_type(), assert->name);
+						if (++j != td->assertions.size()) os << ", ";
+					}
+					os << "}";
+				}
+				if (++i != funcType->forall.size()) os << ", ";
+			}
+			os << ")";
+			typeString = typeString + " -> " + os.str();
+		}
+	}
+
+	std::string GenType::handleGeneric( ReferenceToType * refType ) {
+		if ( ! refType->parameters.empty() ) {
+			std::ostringstream os;
+			// TODO: ???
+			// PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
+			os << "(";
+			// cg.pass.genCommaList( refType->parameters.begin(), refType->parameters.end() );
+			os << ") ";
+			return os.str();
+		}
+		return "";
+	}
+
+	void GenType::postvisit( StructInstType * structInst )  {
+		typeString = "struct " + structInst->name + handleGeneric( structInst ) + " " + typeString;
+		handleQualifiers( structInst );
+	}
+
+	void GenType::postvisit( UnionInstType * unionInst ) {
+		typeString = "union " + unionInst->name + handleGeneric( unionInst ) + " " + typeString;
+		handleQualifiers( unionInst );
+	}
+
+	void GenType::postvisit( EnumInstType * enumInst ) {
+		typeString = "enum " + enumInst->name + " " + typeString;
+		handleQualifiers( enumInst );
+	}
+
+	void GenType::postvisit( TypeInstType * typeInst ) {
+		typeString = typeInst->name + " " + typeString;
+		handleQualifiers( typeInst );
+	}
+
+	void GenType::postvisit( TupleType * tupleType ) {
+		unsigned int i = 0;
+		std::ostringstream os;
+		os << "[";
+		for ( Type * t : *tupleType ) {
+			i++;
+			os << genDemangleType( t, "" ) << (i == tupleType->size() ? "" : ", ");
+		}
+		os << "] ";
+		typeString = os.str() + typeString;
+	}
+
+	void GenType::postvisit( VarArgsType * varArgsType ) {
+		typeString = "__builtin_va_list " + typeString;
+		handleQualifiers( varArgsType );
+	}
+
+	void GenType::postvisit( ZeroType * zeroType ) {
+		// ideally these wouldn't hit codegen at all, but should be safe to make them ints
+		typeString = "zero_t " + typeString;
+		handleQualifiers( zeroType );
+	}
+
+	void GenType::postvisit( OneType * oneType ) {
+		// ideally these wouldn't hit codegen at all, but should be safe to make them ints
+		typeString = "one_t " + typeString;
+		handleQualifiers( oneType );
+	}
+
+	void GenType::postvisit( GlobalScopeType * globalType ) {
+		handleQualifiers( globalType );
+	}
+
+	void GenType::postvisit( QualifiedType * qualType ) {
+		std::ostringstream os;
+		os << genDemangleType( qualType->parent, "" ) << "." << genDemangleType( qualType->child, "" ) << typeString;
+		typeString = os.str();
+		handleQualifiers( qualType );
+	}
+
+	void GenType::handleQualifiers( Type * type ) {
+		if ( type->get_const() ) {
+			typeString = "const " + typeString;
+		} // if
+		if ( type->get_volatile() ) {
+			typeString = "volatile " + typeString;
+		} // if
+		if ( type->get_restrict() ) {
+			typeString = "__restrict " + typeString;
+		} // if
+		if ( type->get_atomic() ) {
+			typeString = "_Atomic " + typeString;
+		} // if
+		if ( type->get_lvalue() ) {
+			// when not generating C code, print lvalue for debugging.
+			typeString = "lvalue " + typeString;
+		}
+	}
+}
+
+
+namespace SymTab {
+	namespace Mangler {
+		namespace {
+			struct StringView {
+			private:
+				std::string str;
+				size_t idx = 0;
+				// typedef Type * (StringView::*parser)(Type::Qualifiers);
+				typedef std::function<Type * (Type::Qualifiers)> parser;
+				std::vector<std::pair<std::string, parser>> parsers;
+			public:
+				StringView(const std::string & str);
+
+				bool done() const { return idx >= str.size(); }
+				char cur() const { assert(! done()); return str[idx]; }
+
+				bool expect(char ch) { return str[idx++] == ch;	}
+				void next(size_t inc = 1) { idx += inc; }
+
+				/// determines if `pref` is a prefix of `str`
+				bool isPrefix(const std::string & pref);
+				bool extractNumber(size_t & out);
+				bool extractName(std::string & out);
+				bool stripMangleName(std::string & name);
+
+				Type * parseFunction(Type::Qualifiers tq);
+				Type * parseTuple(Type::Qualifiers tq);
+				Type * parseVoid(Type::Qualifiers tq);
+				Type * parsePointer(Type::Qualifiers tq);
+				Type * parseStruct(Type::Qualifiers tq);
+
+				Type * parseType();
+				bool parse(std::string & name, Type *& type);
+			};
+
+			StringView::StringView(const std::string & str) : str(str) {
+				// basic types
+				for (size_t k = 0; k < BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
+					parsers.emplace_back(Encoding::basicTypes[k], [this, k](Type::Qualifiers tq) {
+						PRINT( std::cerr << "basic type: " << k << std::endl; )
+						return new BasicType(tq, (BasicType::Kind)k);
+					});
+				}
+				// everything else
+				parsers.emplace_back(Encoding::void_t, [this](Type::Qualifiers tq) { return parseVoid(tq); });
+				parsers.emplace_back(Encoding::function, [this](Type::Qualifiers tq) { return parseFunction(tq); });
+				parsers.emplace_back(Encoding::pointer, [this](Type::Qualifiers tq) { return parsePointer(tq); });
+				parsers.emplace_back(Encoding::tuple, [this](Type::Qualifiers tq) { return parseTuple(tq); });
+				parsers.emplace_back(Encoding::struct_t, [this](Type::Qualifiers tq) { return parseStruct(tq); });
+			}
+
+			bool StringView::extractNumber(size_t & out) {
+				std::stringstream numss;
+				while (isdigit(str[idx])) {
+					numss << str[idx];
+					++idx;
+					if (idx >= str.size()) return false;
+				}
+				if (! (numss >> out)) return false;
+				return true;
+			}
+
+			bool StringView::extractName(std::string & out) {
+				size_t len;
+				if (! extractNumber(len)) return false;
+				if (idx+len >= str.size()) return false;
+				out = str.substr(idx, len);
+				idx += len;
+				return true;
+			}
+
+			bool StringView::isPrefix(const std::string & pref) {
+				if ( pref.size() > str.size()-idx ) return false;
+				auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
+				if (its.first == pref.end()) {
+					idx += pref.size();
+					return true;
+				}
+				return false;
+			}
+
+			// strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
+			bool StringView::stripMangleName(std::string & name) {
+				PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
+				if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
+				if (! isPrefix(Encoding::manglePrefix) || ! isdigit(str.back())) return false;
+
+				// get name
+				if (! extractName(name)) return false;
+
+				// find bounds for type
+				PRINT( std::cerr << idx << " " << str.size() << std::endl; )
+				PRINT( std::cerr << "[");
+				while (isdigit(str.back())) {
+					PRINT(std::cerr << ".");
+					str.pop_back();
+					if (str.size() <= idx) return false;
+				}
+				PRINT( std::cerr << "]" << std::endl );
+				if (str.back() != '_') return false;
+				str.pop_back();
+				PRINT( std::cerr << str.size() << " " << name << " " << str.substr(idx) << std::endl; )
+				return str.size() > idx;
+			}
+
+			Type * StringView::parseFunction(Type::Qualifiers tq) {
+				PRINT( std::cerr << "function..." << std::endl; )
+				if (done()) return nullptr;
+				FunctionType * ftype = new FunctionType( tq, false );
+				Type * retVal = parseType();
+				if (! retVal) return nullptr;
+				PRINT( std::cerr << "with return type: " << retVal << std::endl; )
+				ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr));
+				if (done() || ! expect('_')) return nullptr;
+				while (! done()) {
+					PRINT( std::cerr << "got ch: " << cur() << std::endl; )
+					if (cur() == '_') return ftype;
+					Type * param = parseType();
+					if (! param) return nullptr;
+					PRINT( std::cerr << "with parameter : " << param << std::endl; )
+					ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr));
+				}
+				return nullptr;
+			}
+
+			Type * StringView::parseTuple(Type::Qualifiers tq) {
+				PRINT( std::cerr << "tuple..." << std::endl; )
+				std::list< Type * > types;
+				size_t ncomponents;
+				if (! extractNumber(ncomponents)) return nullptr;
+				for (size_t i = 0; i < ncomponents; ++i) {
+					if (done()) return nullptr;
+					PRINT( std::cerr << "got ch: " << cur() << std::endl; )
+					Type * t = parseType();
+					if (! t) return nullptr;
+					PRINT( std::cerr << "with type : " << t << std::endl; )
+					types.push_back(t);
+				}
+				return new TupleType( tq, types );
+			}
+
+			Type * StringView::parseVoid(Type::Qualifiers tq) {
+				return new VoidType( tq );
+			}
+
+			Type * StringView::parsePointer(Type::Qualifiers tq) {
+				PRINT( std::cerr << "pointer..." << std::endl; )
+				Type * t = parseType();
+				if (! t) return nullptr;
+				return new PointerType( tq, t );
+			}
+
+			Type * StringView::parseStruct(Type::Qualifiers tq) {
+				PRINT( std::cerr << "struct..." << std::endl; )
+				std::string name;
+				if (! extractName(name)) return nullptr;
+				return new StructInstType(tq, name);
+			}
+
+			Type * StringView::parseType() {
+				if (done()) return nullptr;
+
+				// qualifiers
+				Type::Qualifiers tq;
+				while (true) {
+					auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
+						return isPrefix(val.second);
+					});
+					if (qual == Encoding::qualifiers.end()) break;
+					tq |= qual->first;
+				}
+
+				// find the correct type parser and use it
+				auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, parser> & p) {
+					return isPrefix(p.first);
+				});
+				assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), idx);
+				return iter->second(tq);
+			}
+
+			bool StringView::parse(std::string & name, Type *& type) {
+				if (! stripMangleName(name)) return false;
+				PRINT( std::cerr << "stripped name: " << name << std::endl; )
+				Type * t = parseType();
+				if (! t) return false;
+				type = t;
+				return true;
+			}
+		} // namespace
+	} // namespace Mangler
+} // namespace SymTab
+
+extern "C" {
+	std::string cforall_demangle(const std::string & mangleName) {
+		SymTab::Mangler::StringView view(mangleName);
+		std::string name;
+		Type * type = nullptr;
+		if (! view.parse(name, type)) return mangleName;
+		return genDemangleType(type, name);
+	} // extern "C"
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision ac3362c49d6542b7d8c8fb775ea7b0215120bdbd)
+++ src/SymTab/Mangler.cc	(revision 4084928eae5498efed55486197c04b51fe7be79b)
@@ -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 << "__";
+					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,43 +144,11 @@
 			void Mangler::postvisit( VoidType * voidType ) {
 				printQualifiers( voidType );
-				mangleName << "v";
+				mangleName << Encoding::void_t;
 			}
 
 			void Mangler::postvisit( BasicType * basicType ) {
-				static 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
-				};
-				static_assert(
-					sizeof(btLetter)/sizeof(btLetter[0]) == BasicType::NUMBER_OF_BASIC_TYPES,
-					"Each basic type kind should have a corresponding mangler letter"
-				);
-
 				printQualifiers( basicType );
-				assert( basicType->get_kind() < sizeof(btLetter)/sizeof(btLetter[0]) );
-				mangleName << btLetter[ basicType->get_kind() ];
+				assert( basicType->get_kind() < BasicType::NUMBER_OF_BASIC_TYPES );
+				mangleName << Encoding::basicTypes[ basicType->get_kind() ];
 			}
 
@@ -188,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 );
 			}
@@ -195,5 +163,5 @@
 				// TODO: encode dimension
 				printQualifiers( arrayType );
-				mangleName << "A0";
+				mangleName << Encoding::array << "0";
 				maybeAccept( arrayType->base, *visitor );
 			}
@@ -220,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.,
@@ -227,5 +195,6 @@
 				inFunctionType = true;
 				std::list< Type* > returnTypes = getTypes( functionType->returnVals );
-				acceptAll( returnTypes, *visitor );
+				if (returnTypes.empty()) mangleName << Encoding::void_t;
+				else acceptAll( returnTypes, *visitor );
 				mangleName << "_";
 				std::list< Type* > paramTypes = getTypes( functionType->parameters );
@@ -237,5 +206,5 @@
 				printQualifiers( refType );
 
-				mangleName << ( refType->name.length() + prefix.length() ) << prefix << refType->name;
+				mangleName << prefix << refType->name.length() << refType->name;
 
 				if ( mangleGenericParams ) {
@@ -254,13 +223,13 @@
 
 			void Mangler::postvisit( StructInstType * aggregateUseType ) {
-				mangleRef( aggregateUseType, "s" );
+				mangleRef( aggregateUseType, Encoding::struct_t );
 			}
 
 			void Mangler::postvisit( UnionInstType * aggregateUseType ) {
-				mangleRef( aggregateUseType, "u" );
+				mangleRef( aggregateUseType, Encoding::union_t );
 			}
 
 			void Mangler::postvisit( EnumInstType * aggregateUseType ) {
-				mangleRef( aggregateUseType, "e" );
+				mangleRef( aggregateUseType, Encoding::enum_t );
 			}
 
@@ -268,5 +237,5 @@
 				VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
 				if ( varNum == varNums.end() ) {
-					mangleRef( typeInst, "t" );
+					mangleRef( typeInst, Encoding::type );
 				} else {
 					printQualifiers( typeInst );
@@ -292,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 << Encoding::type << 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;
+				}
 			}
 
@@ -370,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
@@ -380,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 ac3362c49d6542b7d8c8fb775ea7b0215120bdbd)
+++ src/SymTab/Mangler.h	(revision 4084928eae5498efed55486197c04b51fe7be79b)
@@ -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 {
@@ -33,6 +40,35 @@
 		/// Mangle ignoring generic type parameters
 		std::string mangleConcrete( Type* ty );
+
+		namespace Encoding {
+			extern const std::string manglePrefix;
+			extern const std::string basicTypes[];
+			extern const std::map<int, std::string> qualifiers;
+
+			extern const std::string void_t;
+			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 struct_t;
+			extern const std::string union_t;
+			extern const std::string enum_t;
+			extern const std::string type;
+
+			extern const std::string autogen;
+			extern const std::string intrinsic;
+		};
 	} // Mangler
 } // SymTab
+
+extern "C" {
+	std::string cforall_demangle(const std::string &);
+}
 
 // Local Variables: //
Index: src/SymTab/ManglerCommon.cc
===================================================================
--- src/SymTab/ManglerCommon.cc	(revision 4084928eae5498efed55486197c04b51fe7be79b)
+++ src/SymTab/ManglerCommon.cc	(revision 4084928eae5498efed55486197c04b51fe7be79b)
@@ -0,0 +1,93 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Mangler.h --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 21:44:03 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Jul 22 09:45:30 2017
+// Update Count     : 15
+//
+
+#include "Mangler.h"
+#include "SynTree/Type.h"
+
+namespace SymTab {
+	namespace Mangler {
+		namespace Encoding {
+			const std::string manglePrefix = "_X";
+
+			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::map<int, std::string> qualifiers = {
+				{ Type::Const, "K" },
+				{ Type::Volatile, "V" },
+				{ Type::Atomic, "A" }, // A = Atomic, A0 = Array and forall parameter...
+				{ Type::Mutex, "X" },
+				{ Type::Lvalue, "L" },
+			};
+
+			const std::string void_t = "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 struct_t = "S";
+			const std::string union_t = "U";
+			const std::string enum_t = "M";
+			const std::string type = "Y";
+
+			const std::string autogen = "autogen__";
+			const std::string intrinsic = "intrinsic__";
+		} // namespace Encoding
+	} // namespace Mangler
+} // namespace SymTab
Index: src/SymTab/demangler.cc
===================================================================
--- src/SymTab/demangler.cc	(revision 4084928eae5498efed55486197c04b51fe7be79b)
+++ src/SymTab/demangler.cc	(revision 4084928eae5498efed55486197c04b51fe7be79b)
@@ -0,0 +1,18 @@
+#include "Mangler.h"
+#include <iostream>
+#include <fstream>
+using namespace std;
+
+void f(const std::string & mangleName) {
+  cout << mangleName << " => " << std::flush << cforall_demangle(mangleName) << endl;
+}
+
+int main() {
+  ifstream in("in-demangle.txt");
+  std::string line;
+  while (getline(in, line)) {
+    if (line.empty()) { cout << "=================================" << endl; continue; }
+    else if (line[0] == '#') continue;
+    f(line);
+  }
+}
Index: src/SymTab/module.mk
===================================================================
--- src/SymTab/module.mk	(revision ac3362c49d6542b7d8c8fb775ea7b0215120bdbd)
+++ src/SymTab/module.mk	(revision 4084928eae5498efed55486197c04b51fe7be79b)
@@ -17,4 +17,5 @@
 SRC += SymTab/Indexer.cc \
        SymTab/Mangler.cc \
+       SymTab/ManglerCommon.cc \
        SymTab/Validate.cc \
        SymTab/FixFunction.cc \
