Index: src/SymTab/Demangle.cc
===================================================================
--- src/SymTab/Demangle.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
+++ src/SymTab/Demangle.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
@@ -0,0 +1,471 @@
+//
+// 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 {
+			// strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
+			bool stripMangleName(const std::string & mangleName, std::string & name, std::string & type) {
+				PRINT( std::cerr << "====== " << mangleName.size() << " " << mangleName << std::endl; )
+				if (mangleName.size() < 4+nameSeparator.size()) return false;
+				if (mangleName[0] != '_' || mangleName[1] != '_' || ! isdigit(mangleName.back())) return false;
+
+				// find bounds for name
+				size_t nameStart = 2;
+				size_t nameEnd = mangleName.rfind(nameSeparator);
+				PRINT( std::cerr << nameStart << " " << nameEnd << std::endl; )
+				if (nameEnd == std::string::npos) return false;
+
+				// find bounds for type
+				size_t typeStart = nameEnd+nameSeparator.size();
+				size_t typeEnd = mangleName.size()-1;
+				PRINT( std::cerr << typeStart << " " << typeEnd << std::endl; )
+				PRINT( std::cerr << "[");
+				while (isdigit(mangleName[typeEnd])) {
+					PRINT(std::cerr << ".");
+					typeEnd--;
+				}
+				PRINT( std::cerr << "]" << std::endl );
+				if (mangleName[typeEnd] != '_') return false;
+				PRINT( std::cerr << typeEnd << std::endl; )
+
+				// trim and return
+				name = mangleName.substr(nameStart, nameEnd-nameStart);
+				type = mangleName.substr(typeStart, typeEnd-typeStart);
+				return true;
+			}
+
+			/// determines if `pref` is a prefix of `str`
+			static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int idx ) {
+				if ( pref.size() > str.size()-idx ) return false;
+				auto its = std::mismatch( pref.begin(), pref.end(), std::next(str.begin(), idx) );
+				return its.first == pref.end();
+			}
+
+			Type * parseType(const std::string & typeString, unsigned int & idx) {
+				if (idx >= typeString.size()) return nullptr;
+
+				// qualifiers
+				Type::Qualifiers tq;
+				while (true) {
+					auto qual = std::find_if(qualifierLetter.begin(), qualifierLetter.end(), [&idx, &typeString](decltype(qualifierLetter)::value_type val) {
+						if (isPrefix(typeString, val.second, idx)) {
+							PRINT( std::cerr << "found qualifier: " << val.second << std::endl; )
+							idx += std::string(val.second).size();
+							return true;
+						}
+						return false;
+					});
+					if (qual == qualifierLetter.end()) break;
+					tq |= qual->first;
+				}
+
+				// basic types
+				const char ** letter = std::find_if(&btLetter[0], &btLetter[numBtLetter], [&idx, &typeString](const std::string & letter) {
+					if (isPrefix(typeString, letter, idx)) {
+						idx += letter.size();
+						return true;
+					}
+					return false;
+				});
+				if (letter != &btLetter[numBtLetter]) {
+					PRINT( std::cerr << "basic type: " << (letter-btLetter) << std::endl; )
+					BasicType::Kind k = (BasicType::Kind)(letter-btLetter);
+					return new BasicType( tq, k );
+				} // BasicType?
+
+				// everything else
+				switch(typeString[idx++]) {
+					case 'F': {
+						PRINT( std::cerr << "function..." << std::endl; )
+						if (idx >= typeString.size()) return nullptr;
+						FunctionType * ftype = new FunctionType( tq, false );
+						Type * retVal = parseType(typeString, idx);
+						if (! retVal) return nullptr;
+						PRINT( std::cerr << "with return type: " << retVal << std::endl; )
+						ftype->returnVals.push_back(ObjectDecl::newObject("", retVal, nullptr));
+						if (idx >= typeString.size() || typeString[idx++] != '_') return nullptr;
+						while (idx < typeString.size()) {
+							PRINT( std::cerr << "got ch: " << typeString[idx] << std::endl; )
+							if (typeString[idx] == '_') break;
+							Type * param = parseType(typeString, idx);
+							if (! param) return nullptr;
+							PRINT( std::cerr << "with parameter : " << param << std::endl; )
+							ftype->parameters.push_back(ObjectDecl::newObject("", param, nullptr));
+						}
+						if (idx >= typeString.size() || typeString[idx] != '_') return nullptr;
+						++idx;
+						return ftype;
+					}
+					case 'v':
+						return new VoidType( tq );
+					case 'T': {
+						PRINT( std::cerr << "tuple..." << std::endl; )
+						std::list< Type * > types;
+						while (idx < typeString.size()) {
+							PRINT( std::cerr << "got ch: " << typeString[idx] << std::endl; )
+							if (typeString[idx] == '_') break;
+							Type * t = parseType(typeString, idx);
+							if (! t) return nullptr;
+							PRINT( std::cerr << "with type : " << t << std::endl; )
+							types.push_back(t);
+						}
+						if (idx >= typeString.size() || typeString[idx] != '_') return nullptr;
+						++idx;
+						return new TupleType( tq, types );
+					}
+					case 'P': {
+						PRINT( std::cerr << "pointer..." << std::endl; )
+						Type * t = parseType(typeString, idx);
+						if (! t) return nullptr;
+						return new PointerType( tq, t );
+					}
+
+					default: assertf(false, "Unhandled type letter: %c at index: %u", typeString[idx], idx);
+				}
+				return nullptr;
+			}
+
+			Type * parseType(const std::string & typeString) {
+				unsigned int idx = 0;
+				return parseType(typeString, idx);
+			}
+		} // namespace
+	} // namespace Mangler
+} // namespace SymTab
+
+extern "C" {
+	std::string cforall_demangle(const std::string & mangleName) {
+		std::string name, type;
+		if (! SymTab::Mangler::stripMangleName(mangleName, name, type)) return mangleName;
+		PRINT( std::cerr << name << " " << type << std::endl; )
+		Type * t = SymTab::Mangler::parseType(type);
+		if (! t) return mangleName;
+		return genDemangleType(t, 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 fd2debf6bc04a25e7312e0b1f5ff93f7d5aff352)
+++ src/SymTab/Mangler.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
@@ -117,5 +117,5 @@
 					mangleName << declaration->get_name();
 				} // if
-				mangleName << "__";
+				mangleName << nameSeparator;
 				maybeAccept( declaration->get_type(), *visitor );
 				if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
@@ -148,38 +148,6 @@
 
 			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]) );
+				assert( basicType->get_kind() < numBtLetter );
 				mangleName << btLetter[ basicType->get_kind() ];
 			}
@@ -227,5 +195,6 @@
 				inFunctionType = true;
 				std::list< Type* > returnTypes = getTypes( functionType->returnVals );
-				acceptAll( returnTypes, *visitor );
+				if (returnTypes.empty()) mangleName << "v";
+				else acceptAll( returnTypes, *visitor );
 				mangleName << "_";
 				std::list< Type* > paramTypes = getTypes( functionType->parameters );
Index: src/SymTab/Mangler.h
===================================================================
--- src/SymTab/Mangler.h	(revision fd2debf6bc04a25e7312e0b1f5ff93f7d5aff352)
+++ src/SymTab/Mangler.h	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
@@ -33,6 +33,15 @@
 		/// Mangle ignoring generic type parameters
 		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;
 	} // Mangler
 } // SymTab
+
+extern "C" {
+	std::string cforall_demangle(const std::string &);
+}
 
 // Local Variables: //
Index: src/SymTab/ManglerCommon.cc
===================================================================
--- src/SymTab/ManglerCommon.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
+++ src/SymTab/ManglerCommon.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
@@ -0,0 +1,64 @@
+//
+// 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 {
+		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"
+		);
+
+		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 nameSeparator = "__cfa__";
+	} // namespace Mangler
+} // namespace SymTab
Index: src/SymTab/demangler.cc
===================================================================
--- src/SymTab/demangler.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
+++ src/SymTab/demangler.cc	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
@@ -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 fd2debf6bc04a25e7312e0b1f5ff93f7d5aff352)
+++ src/SymTab/module.mk	(revision 3bbd012db7d31fbae91c1a4295090ad11eb8ec96)
@@ -17,4 +17,5 @@
 SRC += SymTab/Indexer.cc \
        SymTab/Mangler.cc \
+       SymTab/ManglerCommon.cc \
        SymTab/Validate.cc \
        SymTab/FixFunction.cc \
