Changes in / [adb6a4f1:ecae5860]
- Location:
- src
- Files:
-
- 3 deleted
- 16 edited
-
ResolvExpr/AdjustExprType.cc (modified) (2 diffs)
-
ResolvExpr/Alternative.cc (modified) (3 diffs)
-
ResolvExpr/AlternativeFinder.cc (modified) (16 diffs)
-
ResolvExpr/CastCost.cc (modified) (1 diff)
-
ResolvExpr/ConversionCost.cc (modified) (2 diffs)
-
ResolvExpr/Occurs.cc (modified) (2 diffs)
-
ResolvExpr/PolyCost.cc (modified) (1 diff)
-
ResolvExpr/PtrsAssignable.cc (modified) (2 diffs)
-
ResolvExpr/PtrsCastable.cc (modified) (3 diffs)
-
ResolvExpr/TypeEnvironment.cc (modified) (4 diffs)
-
ResolvExpr/TypeEnvironment.h (modified) (2 diffs)
-
ResolvExpr/Unify.cc (modified) (6 diffs)
-
SynTree/ReferenceToType.cc (modified) (5 diffs)
-
benchmark/Makefile.am (modified) (1 diff)
-
benchmark/Makefile.in (modified) (3 diffs)
-
benchmark/ctxswitch/cfa_thrd2.c (deleted)
-
benchmark/ctxswitch/kos_fibre.cpp (deleted)
-
benchmark/ctxswitch/kos_fibre2.cpp (deleted)
-
libcfa/concurrency/invoke.h (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ResolvExpr/AdjustExprType.cc
radb6a4f1 recae5860 66 66 67 67 Type * AdjustExprType::postmutate( ArrayType * arrayType ) { 68 PointerType *pointerType = new PointerType { arrayType->get_qualifiers(), arrayType->base };68 PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base ); 69 69 arrayType->base = nullptr; 70 70 delete arrayType; … … 73 73 74 74 Type * AdjustExprType::postmutate( FunctionType * functionType ) { 75 return new PointerType { Type::Qualifiers(), functionType };75 return new PointerType( Type::Qualifiers(), functionType ); 76 76 } 77 77 78 78 Type * AdjustExprType::postmutate( TypeInstType * typeInst ) { 79 if ( const EqvClass* eqvClass = env.lookup( typeInst->get_name() ) ) { 80 if ( eqvClass->data.kind == TypeDecl::Ftype ) { 81 return new PointerType{ Type::Qualifiers(), typeInst }; 79 EqvClass eqvClass; 80 if ( env.lookup( typeInst->get_name(), eqvClass ) ) { 81 if ( eqvClass.data.kind == TypeDecl::Ftype ) { 82 PointerType *pointerType = new PointerType( Type::Qualifiers(), typeInst ); 83 return pointerType; 82 84 } 83 85 } else if ( NamedTypeDecl *ntDecl = indexer.lookupType( typeInst->get_name() ) ) { 84 86 if ( TypeDecl *tyDecl = dynamic_cast< TypeDecl* >( ntDecl ) ) { 85 87 if ( tyDecl->get_kind() == TypeDecl::Ftype ) { 86 return new PointerType{ Type::Qualifiers(), typeInst }; 88 PointerType *pointerType = new PointerType( Type::Qualifiers(), typeInst ); 89 return pointerType; 87 90 } // if 88 91 } // if -
src/ResolvExpr/Alternative.cc
radb6a4f1 recae5860 27 27 28 28 namespace ResolvExpr { 29 Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( nullptr) {}29 Alternative::Alternative() : cost( Cost::zero ), cvtCost( Cost::zero ), expr( 0 ) {} 30 30 31 31 Alternative::Alternative( Expression *expr, const TypeEnvironment &env, const Cost& cost ) … … 48 48 } 49 49 50 Alternative::Alternative( Alternative && other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( other.expr ), env( std::move( other.env )) {50 Alternative::Alternative( Alternative && other ) : cost( other.cost ), cvtCost( other.cvtCost ), expr( other.expr ), env( other.env ) { 51 51 other.expr = nullptr; 52 52 } … … 58 58 cvtCost = other.cvtCost; 59 59 expr = other.expr; 60 env = std::move( other.env );60 env = other.env; 61 61 other.expr = nullptr; 62 62 return *this; -
src/ResolvExpr/AlternativeFinder.cc
radb6a4f1 recae5860 102 102 void addAnonConversions( const Alternative & alt ); 103 103 /// Adds alternatives for member expressions, given the aggregate, conversion cost for that aggregate, and name of the member 104 template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name);104 template< typename StructOrUnionType > void addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ); 105 105 /// Adds alternatives for member expressions where the left side has tuple type 106 106 void addTupleMembers( TupleType * tupleType, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ); … … 307 307 308 308 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->result ) ) { 309 addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" ); 309 NameExpr nameExpr( "" ); 310 addAggMembers( structInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr ); 310 311 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->result ) ) { 311 addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, "" ); 312 NameExpr nameExpr( "" ); 313 addAggMembers( unionInst, aggrExpr.get(), alt.cost+Cost::safe, alt.env, &nameExpr ); 312 314 } // if 313 315 } 314 316 315 317 template< typename StructOrUnionType > 316 void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, const std::string & name ) { 318 void AlternativeFinder::Finder::addAggMembers( StructOrUnionType *aggInst, Expression *expr, const Cost &newCost, const TypeEnvironment & env, Expression * member ) { 319 // by this point, member must be a name expr 320 NameExpr * nameExpr = dynamic_cast< NameExpr * >( member ); 321 if ( ! nameExpr ) return; 322 const std::string & name = nameExpr->name; 317 323 std::list< Declaration* > members; 318 324 aggInst->lookup( name, members ); 319 325 320 for ( Declaration * decl : members ) { 321 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( decl ) ) { 322 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so 323 // can't construct in place and use vector::back 324 Alternative newAlt( new MemberExpr( dwt, expr->clone() ), env, newCost ); 325 renameTypes( newAlt.expr ); 326 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression. 327 alternatives.push_back( std::move(newAlt) ); 326 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) { 327 if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType* >( *i ) ) { 328 alternatives.push_back( Alternative( new MemberExpr( dwt, expr->clone() ), env, newCost ) ); 329 renameTypes( alternatives.back().expr ); 330 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a member expression. 328 331 } else { 329 332 assert( false ); … … 466 469 } 467 470 471 // /// Map of declaration uniqueIds (intended to be the assertions in an AssertionSet) to their parents and the number of times they've been included 472 //typedef std::unordered_map< UniqueId, std::unordered_map< UniqueId, unsigned > > AssertionParentSet; 473 468 474 static const int recursionLimit = /*10*/ 4; ///< Limit to depth of recursion satisfaction 475 //static const unsigned recursionParentLimit = 1; ///< Limit to the number of times an assertion can recursively use itself 469 476 470 477 void addToIndexer( AssertionSet &assertSet, SymTab::Indexer &indexer ) { … … 477 484 478 485 template< typename ForwardIterator, typename OutputIterator > 479 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, int level, const SymTab::Indexer &indexer, OutputIterator out ) { 486 void inferRecursive( ForwardIterator begin, ForwardIterator end, const Alternative &newAlt, OpenVarSet &openVars, const SymTab::Indexer &decls, const AssertionSet &newNeed, /*const AssertionParentSet &needParents,*/ 487 int level, const SymTab::Indexer &indexer, OutputIterator out ) { 480 488 if ( begin == end ) { 481 489 if ( newNeed.empty() ) { … … 495 503 printAssertionSet( newNeed, std::cerr, 8 ); 496 504 ) 497 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, level+1, indexer, out );505 inferRecursive( newNeed.begin(), newNeed.end(), newAlt, openVars, decls, newerNeed, /*needParents,*/ level+1, indexer, out ); 498 506 return; 499 507 } … … 502 510 ForwardIterator cur = begin++; 503 511 if ( ! cur->second.isUsed ) { 504 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, level, indexer, out );512 inferRecursive( begin, end, newAlt, openVars, decls, newNeed, /*needParents,*/ level, indexer, out ); 505 513 return; // xxx - should this continue? previously this wasn't here, and it looks like it should be 506 514 } … … 555 563 } 556 564 565 //AssertionParentSet newNeedParents( needParents ); 566 // skip repeatingly-self-recursive assertion satisfaction 567 // DOESN'T WORK: grandchild nodes conflict with their cousins 568 //if ( newNeedParents[ curDecl->get_uniqueId() ][ candDecl->get_uniqueId() ]++ > recursionParentLimit ) continue; 569 557 570 Expression *varExpr = data.combine( newerAlt.cvtCost ); 558 571 delete varExpr->get_result(); … … 572 585 // XXX: this is a memory leak, but adjType can't be deleted because it might contain assertions 573 586 (*inferParameters)[ curDecl->get_uniqueId() ] = ParamEntry( candidate->get_uniqueId(), adjType->clone(), curDecl->get_type()->clone(), varExpr ); 574 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, level, indexer, out );587 inferRecursive( begin, end, newerAlt, newOpenVars, newDecls, newerNeed, /*newNeedParents,*/ level, indexer, out ); 575 588 } else { 576 589 delete adjType; … … 594 607 addToIndexer( have, decls ); 595 608 AssertionSet newNeed; 609 //AssertionParentSet needParents; 596 610 PRINT( 597 611 std::cerr << "env is: " << std::endl; … … 600 614 ) 601 615 602 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, 0, indexer, out );616 inferRecursive( need.begin(), need.end(), newAlt, openVars, decls, newNeed, /*needParents,*/ 0, indexer, out ); 603 617 // PRINT( 604 618 // std::cerr << "declaration 14 is "; … … 1079 1093 AlternativeFinder funcOpFinder( indexer, env ); 1080 1094 // it's ok if there aren't any defined function ops 1081 funcOpFinder.maybeFind( opExpr );1095 funcOpFinder.maybeFind( opExpr); 1082 1096 PRINT( 1083 1097 std::cerr << "known function ops:" << std::endl; … … 1116 1130 } 1117 1131 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( func->expr->result->stripReferences() ) ) { // handle ftype (e.g. *? on function pointer) 1118 if ( const EqvClass *eqvClass = func->env.lookup( typeInst->name ) ) { 1119 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass->type ) ) { 1132 EqvClass eqvClass; 1133 if ( func->env.lookup( typeInst->name, eqvClass ) && eqvClass.type ) { 1134 if ( FunctionType *function = dynamic_cast< FunctionType* >( eqvClass.type ) ) { 1120 1135 Alternative newFunc( *func ); 1121 1136 referenceToRvalueConversion( newFunc.expr, newFunc.cost ); … … 1332 1347 } 1333 1348 1334 namespace {1335 /// Gets name from untyped member expression (member must be NameExpr)1336 const std::string& get_member_name( UntypedMemberExpr *memberExpr ) {1337 NameExpr * nameExpr = dynamic_cast< NameExpr * >( memberExpr->get_member() );1338 assert( nameExpr );1339 return nameExpr->get_name();1340 }1341 }1342 1343 1349 void AlternativeFinder::Finder::postvisit( UntypedMemberExpr *memberExpr ) { 1344 1350 AlternativeFinder funcFinder( indexer, env ); … … 1353 1359 // find member of the given type 1354 1360 if ( StructInstType *structInst = dynamic_cast< StructInstType* >( aggrExpr->get_result() ) ) { 1355 addAggMembers( structInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );1361 addAggMembers( structInst, aggrExpr, cost, agg->env, memberExpr->get_member() ); 1356 1362 } else if ( UnionInstType *unionInst = dynamic_cast< UnionInstType* >( aggrExpr->get_result() ) ) { 1357 addAggMembers( unionInst, aggrExpr, cost, agg->env, get_member_name(memberExpr) );1363 addAggMembers( unionInst, aggrExpr, cost, agg->env, memberExpr->get_member() ); 1358 1364 } else if ( TupleType * tupleType = dynamic_cast< TupleType * >( aggrExpr->get_result() ) ) { 1359 1365 addTupleMembers( tupleType, aggrExpr, cost, agg->env, memberExpr->get_member() ); … … 1373 1379 Cost cost = Cost::zero; 1374 1380 Expression * newExpr = data.combine( cost ); 1375 1376 // addAnonAlternatives uses vector::push_back, which invalidates references to existing elements, so 1377 // can't construct in place and use vector::back 1378 Alternative newAlt( newExpr, env, Cost::zero, cost ); 1381 alternatives.push_back( Alternative( newExpr, env, Cost::zero, cost ) ); 1379 1382 PRINT( 1380 1383 std::cerr << "decl is "; … … 1385 1388 std::cerr << std::endl; 1386 1389 ) 1387 renameTypes( newAlt.expr ); 1388 addAnonConversions( newAlt ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression. 1389 alternatives.push_back( std::move(newAlt) ); 1390 renameTypes( alternatives.back().expr ); 1391 addAnonConversions( alternatives.back() ); // add anonymous member interpretations whenever an aggregate value type is seen as a name expression. 1390 1392 } // for 1391 1393 } -
src/ResolvExpr/CastCost.cc
radb6a4f1 recae5860 43 43 Cost castCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 44 44 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 45 if ( const EqvClass* eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 46 if ( eqvClass->type ) { 47 return castCost( src, eqvClass->type, indexer, env ); 45 EqvClass eqvClass; 46 NamedTypeDecl *namedType; 47 if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) { 48 if ( eqvClass.type ) { 49 return castCost( src, eqvClass.type, indexer, env ); 48 50 } else { 49 51 return Cost::infinity; 50 52 } 51 } else if ( NamedTypeDecl *namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) {53 } else if ( ( namedType = indexer.lookupType( destAsTypeInst->get_name() ) ) ) { 52 54 // all typedefs should be gone by this point 53 55 TypeDecl *type = strict_dynamic_cast< TypeDecl* >( namedType ); -
src/ResolvExpr/ConversionCost.cc
radb6a4f1 recae5860 42 42 Cost conversionCost( Type *src, Type *dest, const SymTab::Indexer &indexer, const TypeEnvironment &env ) { 43 43 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 44 EqvClass eqvClass; 45 NamedTypeDecl *namedType; 44 46 PRINT( std::cerr << "type inst " << destAsTypeInst->name; ) 45 if ( const EqvClass* eqvClass = env.lookup( destAsTypeInst->name) ) {46 if ( eqvClass ->type ) {47 return conversionCost( src, eqvClass ->type, indexer, env );47 if ( env.lookup( destAsTypeInst->name, eqvClass ) ) { 48 if ( eqvClass.type ) { 49 return conversionCost( src, eqvClass.type, indexer, env ); 48 50 } else { 49 51 return Cost::infinity; 50 52 } 51 } else if ( NamedTypeDecl *namedType = indexer.lookupType( destAsTypeInst->name) ) {53 } else if ( ( namedType = indexer.lookupType( destAsTypeInst->name ) ) ) { 52 54 PRINT( std::cerr << " found" << std::endl; ) 53 55 TypeDecl *type = dynamic_cast< TypeDecl* >( namedType ); … … 367 369 368 370 void ConversionCost::postvisit( TypeInstType *inst ) { 369 if ( const EqvClass *eqvClass = env.lookup( inst->name ) ) { 370 cost = costFunc( eqvClass->type, dest, indexer, env ); 371 EqvClass eqvClass; 372 NamedTypeDecl *namedType; 373 if ( env.lookup( inst->name, eqvClass ) ) { 374 cost = costFunc( eqvClass.type, dest, indexer, env ); 371 375 } else if ( TypeInstType *destAsInst = dynamic_cast< TypeInstType* >( dest ) ) { 372 376 if ( inst->name == destAsInst->name ) { 373 377 cost = Cost::zero; 374 378 } 375 } else if ( NamedTypeDecl *namedType = indexer.lookupType( inst->name) ) {379 } else if ( ( namedType = indexer.lookupType( inst->name ) ) ) { 376 380 TypeDecl *type = dynamic_cast< TypeDecl* >( namedType ); 377 381 // all typedefs should be gone by this point -
src/ResolvExpr/Occurs.cc
radb6a4f1 recae5860 38 38 39 39 Occurs::Occurs( std::string varName, const TypeEnvironment & env ) : result( false ), tenv( env ) { 40 if ( const EqvClass *eqvClass = tenv.lookup( varName ) ) { 41 eqvVars = eqvClass->vars; 40 EqvClass eqvClass; 41 if ( tenv.lookup( varName, eqvClass ) ) { 42 eqvVars = eqvClass.vars; 42 43 } else { 43 44 eqvVars.insert( varName ); … … 46 47 47 48 void Occurs::previsit( TypeInstType * typeInst ) { 48 /// std::cerr << "searching for vars: "; 49 EqvClass eqvClass; 50 /// std::cerr << "searching for vars: "; 49 51 /// std::copy( eqvVars.begin(), eqvVars.end(), std::ostream_iterator< std::string >( std::cerr, " " ) ); 50 52 /// std::cerr << std::endl; 51 53 if ( eqvVars.find( typeInst->get_name() ) != eqvVars.end() ) { 52 54 result = true; 53 } else if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name()) ) {54 if ( eqvClass ->type ) {55 } else if ( tenv.lookup( typeInst->get_name(), eqvClass ) ) { 56 if ( eqvClass.type ) { 55 57 /// std::cerr << typeInst->get_name() << " is bound to"; 56 58 /// eqvClass.type->print( std::cerr ); 57 59 /// std::cerr << std::endl; 58 eqvClass ->type->accept( *visitor );60 eqvClass.type->accept( *visitor ); 59 61 } // if 60 62 } // if -
src/ResolvExpr/PolyCost.cc
radb6a4f1 recae5860 39 39 40 40 void PolyCost::previsit(TypeInstType * typeInst) { 41 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->name ) ) { 42 if ( eqvClass->type ) { 43 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass->type ) ) { 41 EqvClass eqvClass; 42 if ( tenv.lookup( typeInst->name, eqvClass ) ) { 43 if ( eqvClass.type ) { 44 if ( TypeInstType * otherTypeInst = dynamic_cast< TypeInstType* >( eqvClass.type ) ) { 44 45 if ( indexer.lookupType( otherTypeInst->name ) ) { 45 46 // bound to opaque type -
src/ResolvExpr/PtrsAssignable.cc
radb6a4f1 recae5860 51 51 // std::cerr << "assignable: " << src << " | " << dest << std::endl; 52 52 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 53 if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 54 return ptrsAssignable( src, eqvClass->type, env ); 53 EqvClass eqvClass; 54 if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) { 55 return ptrsAssignable( src, eqvClass.type, env ); 55 56 } // if 56 57 } // if … … 94 95 void PtrsAssignable::postvisit( __attribute__((unused)) TraitInstType *inst ) {} 95 96 void PtrsAssignable::postvisit( TypeInstType *inst ) { 96 if ( const EqvClass *eqvClass = env.lookup( inst->get_name() ) ) { 97 if ( eqvClass->type ) { 98 // T * = S * for any S depends on the type bound to T 99 result = ptrsAssignable( eqvClass->type, dest, env ); 100 } 97 EqvClass eqvClass; 98 if ( env.lookup( inst->get_name(), eqvClass ) && eqvClass.type ) { 99 // T * = S * for any S depends on the type bound to T 100 result = ptrsAssignable( eqvClass.type, dest, env ); 101 101 } // if 102 102 } -
src/ResolvExpr/PtrsCastable.cc
radb6a4f1 recae5860 57 57 return -1; 58 58 } else if ( TypeInstType *typeInst = dynamic_cast< TypeInstType* >( src ) ) { 59 EqvClass eqvClass; 59 60 if ( NamedTypeDecl *ntDecl = indexer.lookupType( typeInst->get_name() ) ) { 60 61 if ( TypeDecl *tyDecl = dynamic_cast< TypeDecl* >( ntDecl ) ) { … … 63 64 } // if 64 65 } //if 65 } else if ( const EqvClass *eqvClass = env.lookup( typeInst->get_name()) ) {66 if ( eqvClass ->data.kind == TypeDecl::Ftype ) {66 } else if ( env.lookup( typeInst->get_name(), eqvClass ) ) { 67 if ( eqvClass.data.kind == TypeDecl::Ftype ) { 67 68 return -1; 68 69 } // if … … 78 79 int ptrsCastable( Type *src, Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer ) { 79 80 if ( TypeInstType *destAsTypeInst = dynamic_cast< TypeInstType* >( dest ) ) { 80 if ( const EqvClass *eqvClass = env.lookup( destAsTypeInst->get_name() ) ) { 81 EqvClass eqvClass; 82 if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) { 81 83 // xxx - should this be ptrsCastable? 82 return ptrsAssignable( src, eqvClass ->type, env );84 return ptrsAssignable( src, eqvClass.type, env ); 83 85 } // if 84 86 } // if -
src/ResolvExpr/TypeEnvironment.cc
radb6a4f1 recae5860 17 17 #include <algorithm> // for copy, set_intersection 18 18 #include <iterator> // for ostream_iterator, insert_iterator 19 #include <utility> // for pair , move19 #include <utility> // for pair 20 20 21 21 #include "Common/utility.h" // for maybeClone … … 44 44 45 45 void EqvClass::initialize( const EqvClass &src, EqvClass &dest ) { 46 initialize( src, dest, src.type );47 }48 49 void EqvClass::initialize( const EqvClass &src, EqvClass &dest, const Type *ty ) {50 46 dest.vars = src.vars; 51 dest.type = maybeClone( ty);47 dest.type = maybeClone( src.type ); 52 48 dest.allowWidening = src.allowWidening; 53 49 dest.data = src.data; 54 50 } 55 51 56 EqvClass::EqvClass() : type( nullptr), allowWidening( true ) {52 EqvClass::EqvClass() : type( 0 ), allowWidening( true ) { 57 53 } 58 54 59 55 EqvClass::EqvClass( const EqvClass &other ) { 60 56 initialize( other, *this ); 61 }62 63 EqvClass::EqvClass( const EqvClass &other, const Type *ty ) {64 initialize( other, *this, ty );65 57 } 66 58 … … 90 82 } 91 83 92 const EqvClass* TypeEnvironment::lookup( const std::string &var) const {84 bool TypeEnvironment::lookup( const std::string &var, EqvClass &eqvClass ) const { 93 85 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) { 94 86 if ( i->vars.find( var ) != i->vars.end() ) { 95 87 /// std::cout << var << " is in class "; 96 88 /// i->print( std::cout ); 97 return &*i; 89 eqvClass = *i; 90 return true; 98 91 } 99 92 /// std::cout << var << " is not in class "; 100 93 /// i->print( std::cout ); 101 94 } // for 102 return nullptr; 103 } 104 105 /// Removes any class from env that intersects eqvClass 106 void filterOverlappingClasses( std::list<EqvClass> &env, const EqvClass &eqvClass ) { 107 for ( auto i = env.begin(); i != env.end(); ) { 108 auto next = i; 109 ++next; 110 std::set<std::string> intersection; 111 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), 112 std::inserter( intersection, intersection.begin() ) ); 113 if ( ! intersection.empty() ) { env.erase( i ); } 95 return false; 96 } 97 98 void TypeEnvironment::add( const EqvClass &eqvClass ) { 99 std::list< EqvClass >::iterator i = env.begin(); 100 while ( i != env.end() ) { 101 std::list< EqvClass >::iterator next = i; 102 next++; 103 std::set< std::string > intersection; 104 std::set_intersection( i->vars.begin(), i->vars.end(), eqvClass.vars.begin(), eqvClass.vars.end(), std::inserter( intersection, intersection.begin() ) ); 105 if ( ! intersection.empty() ) { 106 env.erase( i ); 107 } // if 114 108 i = next; 115 } 116 } 117 118 void TypeEnvironment::add( const EqvClass &eqvClass ) { 119 filterOverlappingClasses( env, eqvClass ); 120 env.push_back( eqvClass ); 121 } 122 123 void TypeEnvironment::add( EqvClass &&eqvClass ) { 124 filterOverlappingClasses( env, eqvClass ); 125 env.push_back( std::move(eqvClass) ); 109 } // while 110 env.insert( env.end(), eqvClass ); 126 111 } 127 112 … … 174 159 175 160 void TypeEnvironment::print( std::ostream &os, Indenter indent ) const { 176 for ( const EqvClass & theClass : env) {177 theClass.print( os, indent );161 for ( std::list< EqvClass >::const_iterator i = env.begin(); i != env.end(); ++i ) { 162 i->print( os, indent ); 178 163 } // for 179 164 } -
src/ResolvExpr/TypeEnvironment.h
radb6a4f1 recae5860 73 73 74 74 void initialize( const EqvClass &src, EqvClass &dest ); 75 void initialize( const EqvClass &src, EqvClass &dest, const Type *ty );76 75 EqvClass(); 77 76 EqvClass( const EqvClass &other ); 78 EqvClass( const EqvClass &other, const Type *ty );79 77 EqvClass &operator=( const EqvClass &other ); 80 78 ~EqvClass(); … … 84 82 class TypeEnvironment { 85 83 public: 86 const EqvClass* lookup( const std::string &var) const;84 bool lookup( const std::string &var, EqvClass &eqvClass ) const; 87 85 void add( const EqvClass &eqvClass ); 88 void add( EqvClass &&eqvClass );89 86 void add( const Type::ForallList &tyDecls ); 90 87 void add( const TypeSubstitution & sub ); -
src/ResolvExpr/Unify.cc
radb6a4f1 recae5860 20 20 #include <set> // for set 21 21 #include <string> // for string, operator==, operator!=, bas... 22 #include <utility> // for pair , move22 #include <utility> // for pair 23 23 24 24 #include "Common/PassVisitor.h" // for PassVisitor … … 166 166 return false; 167 167 } // if 168 if ( const EqvClass *curClass = env.lookup( typeInst->get_name() ) ) { 169 if ( curClass->type ) { 168 EqvClass curClass; 169 if ( env.lookup( typeInst->get_name(), curClass ) ) { 170 if ( curClass.type ) { 170 171 Type *common = 0; 171 172 // attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to 172 std::unique_ptr< Type > newType( curClass ->type->clone() );173 std::unique_ptr< Type > newType( curClass.type->clone() ); 173 174 newType->get_qualifiers() = typeInst->get_qualifiers(); 174 if ( unifyInexact( newType.get(), other, env, needAssertions, haveAssertions, openVars, widenMode & WidenMode( curClass ->allowWidening, true ), indexer, common ) ) {175 if ( unifyInexact( newType.get(), other, env, needAssertions, haveAssertions, openVars, widenMode & WidenMode( curClass.allowWidening, true ), indexer, common ) ) { 175 176 if ( common ) { 176 177 common->get_qualifiers() = Type::Qualifiers(); 177 env.add( EqvClass{ *curClass, common } ); 178 delete curClass.type; 179 curClass.type = common; 180 env.add( curClass ); 178 181 } // if 179 182 return true; … … 182 185 } // if 183 186 } else { 184 EqvClass newClass { *curClass, other };185 newClass.type->get_qualifiers() = Type::Qualifiers();186 newClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond;187 env.add( std::move(newClass));187 curClass.type = other->clone(); 188 curClass.type->get_qualifiers() = Type::Qualifiers(); 189 curClass.allowWidening = widenMode.widenFirst && widenMode.widenSecond; 190 env.add( curClass ); 188 191 } // if 189 192 } else { … … 201 204 bool bindVarToVar( TypeInstType *var1, TypeInstType *var2, const TypeDecl::Data & data, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer ) { 202 205 bool result = true; 203 const EqvClass *class1 = env.lookup( var1->get_name() );204 const EqvClass *class2 = env.lookup( var2->get_name() );206 EqvClass class1, class2; 207 bool hasClass1 = false, hasClass2 = false; 205 208 bool widen1 = false, widen2 = false; 206 Type *type1 = nullptr, *type2 = nullptr; 207 208 if ( class1 ) { 209 if ( class1->type ) { 210 if ( occurs( class1->type, var2->get_name(), env ) ) { 209 Type *type1 = 0, *type2 = 0; 210 211 if ( env.lookup( var1->get_name(), class1 ) ) { 212 hasClass1 = true; 213 if ( class1.type ) { 214 if ( occurs( class1.type, var2->get_name(), env ) ) { 211 215 return false; 212 216 } // if 213 type1 = class1->type->clone(); 214 } // if 215 widen1 = widenMode.widenFirst && class1->allowWidening; 216 } // if 217 if ( class2 ) { 218 if ( class2->type ) { 219 if ( occurs( class2->type, var1->get_name(), env ) ) { 217 type1 = class1.type->clone(); 218 } // if 219 widen1 = widenMode.widenFirst && class1.allowWidening; 220 } // if 221 if ( env.lookup( var2->get_name(), class2 ) ) { 222 hasClass2 = true; 223 if ( class2.type ) { 224 if ( occurs( class2.type, var1->get_name(), env ) ) { 220 225 return false; 221 226 } // if 222 type2 = class2 ->type->clone();223 } // if 224 widen2 = widenMode.widenSecond && class2 ->allowWidening;227 type2 = class2.type->clone(); 228 } // if 229 widen2 = widenMode.widenSecond && class2.allowWidening; 225 230 } // if 226 231 … … 230 235 Type *common = 0; 231 236 if ( unifyInexact( type1, type2, env, needAssertions, haveAssertions, openVars, newWidenMode, indexer, common ) ) { 232 EqvClass newClass1 = *class1; 233 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() ); 234 newClass1.allowWidening = widen1 && widen2; 237 class1.vars.insert( class2.vars.begin(), class2.vars.end() ); 238 class1.allowWidening = widen1 && widen2; 235 239 if ( common ) { 236 240 common->get_qualifiers() = Type::Qualifiers(); 237 delete newClass1.type;238 newClass1.type = common;241 delete class1.type; 242 class1.type = common; 239 243 } // if 240 env.add( std::move(newClass1));244 env.add( class1 ); 241 245 } else { 242 246 result = false; 243 247 } // if 244 } else if ( class1 && class2 ) {248 } else if ( hasClass1 && hasClass2 ) { 245 249 if ( type1 ) { 246 EqvClass newClass1 = *class1; 247 newClass1.vars.insert( class2->vars.begin(), class2->vars.end() ); 248 newClass1.allowWidening = widen1; 249 env.add( std::move(newClass1) ); 250 class1.vars.insert( class2.vars.begin(), class2.vars.end() ); 251 class1.allowWidening = widen1; 252 env.add( class1 ); 250 253 } else { 251 EqvClass newClass2 = *class2; 252 newClass2.vars.insert( class1->vars.begin(), class1->vars.end() ); 253 newClass2.allowWidening = widen2; 254 env.add( std::move(newClass2) ); 255 } // if 256 } else if ( class1 ) { 257 EqvClass newClass1 = *class1; 258 newClass1.vars.insert( var2->get_name() ); 259 newClass1.allowWidening = widen1; 260 env.add( std::move(newClass1) ); 261 } else if ( class2 ) { 262 EqvClass newClass2 = *class2; 263 newClass2.vars.insert( var1->get_name() ); 264 newClass2.allowWidening = widen2; 265 env.add( std::move(newClass2) ); 254 class2.vars.insert( class1.vars.begin(), class1.vars.end() ); 255 class2.allowWidening = widen2; 256 env.add( class2 ); 257 } // if 258 } else if ( hasClass1 ) { 259 class1.vars.insert( var2->get_name() ); 260 class1.allowWidening = widen1; 261 env.add( class1 ); 262 } else if ( hasClass2 ) { 263 class2.vars.insert( var1->get_name() ); 264 class2.allowWidening = widen2; 265 env.add( class2 ); 266 266 } else { 267 267 EqvClass newClass; … … 539 539 void premutate( TypeInstType * ) { visit_children = false; } 540 540 Type * postmutate( TypeInstType * typeInst ) { 541 if ( const EqvClass *eqvClass = tenv.lookup( typeInst->get_name() ) ) { 542 // expand ttype parameter into its actual type 543 if ( eqvClass->data.kind == TypeDecl::Ttype && eqvClass->type ) { 544 delete typeInst; 545 return eqvClass->type->clone(); 541 EqvClass eqvClass; 542 if ( tenv.lookup( typeInst->get_name(), eqvClass ) ) { 543 if ( eqvClass.data.kind == TypeDecl::Ttype ) { 544 // expand ttype parameter into its actual type 545 if ( eqvClass.type ) { 546 delete typeInst; 547 return eqvClass.type->clone(); 548 } 546 549 } 547 550 } -
src/SynTree/ReferenceToType.cc
radb6a4f1 recae5860 50 50 51 51 namespace { 52 void doLookup( const std::list< Declaration * > & members, const std::string & name, std::list< Declaration* > &foundDecls ) {53 for ( Declaration * decl : members) {54 if ( decl->name== name ) {55 foundDecls.push_back( decl);52 void doLookup( const std::list< Declaration* > &members, const std::string &name, std::list< Declaration* > &foundDecls ) { 53 for ( std::list< Declaration* >::const_iterator i = members.begin(); i != members.end(); ++i ) { 54 if ( (*i)->get_name() == name ) { 55 foundDecls.push_back( *i ); 56 56 } // if 57 57 } // for … … 60 60 61 61 StructInstType::StructInstType( const Type::Qualifiers & tq, StructDecl * baseStruct, const std::list< Attribute * > & attributes ) : 62 Parent( tq, baseStruct-> name, attributes ), baseStruct( baseStruct ) {}62 Parent( tq, baseStruct->get_name(), attributes ), baseStruct( baseStruct ) {} 63 63 64 64 std::string StructInstType::typeString() const { return "struct"; } … … 84 84 void StructInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { 85 85 assert( baseStruct ); 86 doLookup( baseStruct-> members, name, foundDecls );86 doLookup( baseStruct->get_members(), name, foundDecls ); 87 87 } 88 88 … … 103 103 104 104 UnionInstType::UnionInstType( const Type::Qualifiers & tq, UnionDecl * baseUnion, const std::list< Attribute * > & attributes ) : 105 Parent( tq, baseUnion-> name, attributes ), baseUnion( baseUnion ) {}105 Parent( tq, baseUnion->get_name(), attributes ), baseUnion( baseUnion ) {} 106 106 107 107 std::string UnionInstType::typeString() const { return "union"; } … … 127 127 void UnionInstType::lookup( const std::string &name, std::list< Declaration* > &foundDecls ) const { 128 128 assert( baseUnion ); 129 doLookup( baseUnion-> members, name, foundDecls );129 doLookup( baseUnion->get_members(), name, foundDecls ); 130 130 } 131 131 -
src/benchmark/Makefile.am
radb6a4f1 recae5860 96 96 ctxswitch-cfa_coroutine.run \ 97 97 ctxswitch-cfa_thread.run \ 98 ctxswitch-cfa_thread2.run \99 98 ctxswitch-upp_coroutine.run \ 100 99 ctxswitch-upp_thread.run \ 101 -ctxswitch-kos_fibre.run \102 -ctxswitch-kos_fibre2.run \103 100 ctxswitch-goroutine.run \ 104 101 ctxswitch-java_thread.run 105 102 103 ctxswitch-cfa_coroutine$(EXEEXT): 104 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 105 106 ctxswitch-cfa_thread$(EXEEXT): 107 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 108 109 ctxswitch-upp_coroutine$(EXEEXT): 110 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 111 112 ctxswitch-upp_thread$(EXEEXT): 113 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 114 106 115 ctxswitch-pthread$(EXEEXT): 107 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 108 109 ctxswitch-cfa_coroutine$(EXEEXT): 110 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 111 112 ctxswitch-cfa_thread$(EXEEXT): 113 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 114 115 ctxswitch-cfa_thread2$(EXEEXT): 116 @${CC} ctxswitch/cfa_thrd2.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 117 118 ctxswitch-upp_coroutine$(EXEEXT): 119 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 120 121 ctxswitch-upp_thread$(EXEEXT): 122 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 123 124 ctxswitch-kos_fibre$(EXEEXT): 125 @${CXX} ctxswitch/kos_fibre.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 126 127 ctxswitch-kos_fibre2$(EXEEXT): 128 @${CXX} ctxswitch/kos_fibre2.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 116 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 129 117 130 118 ctxswitch-goroutine$(EXEEXT): -
src/benchmark/Makefile.in
radb6a4f1 recae5860 509 509 ctxswitch-cfa_coroutine.run \ 510 510 ctxswitch-cfa_thread.run \ 511 ctxswitch-cfa_thread2.run \512 511 ctxswitch-upp_coroutine.run \ 513 512 ctxswitch-upp_thread.run \ 514 -ctxswitch-kos_fibre.run \515 -ctxswitch-kos_fibre2.run \516 513 ctxswitch-goroutine.run \ 517 514 ctxswitch-java_thread.run 518 515 516 ctxswitch-cfa_coroutine$(EXEEXT): 517 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 518 519 ctxswitch-cfa_thread$(EXEEXT): 520 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 521 522 ctxswitch-upp_coroutine$(EXEEXT): 523 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 524 525 ctxswitch-upp_thread$(EXEEXT): 526 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 527 519 528 ctxswitch-pthread$(EXEEXT): 520 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 521 522 ctxswitch-cfa_coroutine$(EXEEXT): 523 @${CC} ctxswitch/cfa_cor.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 524 525 ctxswitch-cfa_thread$(EXEEXT): 526 @${CC} ctxswitch/cfa_thrd.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 527 528 ctxswitch-cfa_thread2$(EXEEXT): 529 @${CC} ctxswitch/cfa_thrd2.c -DBENCH_N=50000000 -I. -nodebug -lrt -quiet @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 530 531 ctxswitch-upp_coroutine$(EXEEXT): 532 @u++ ctxswitch/upp_cor.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 533 534 ctxswitch-upp_thread$(EXEEXT): 535 @u++ ctxswitch/upp_thrd.cc -DBENCH_N=50000000 -I. -nodebug -lrt -quiet ${AM_CFLAGS} ${CFLAGS} ${ccflags} 536 537 ctxswitch-kos_fibre$(EXEEXT): 538 @${CXX} ctxswitch/kos_fibre.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 539 540 ctxswitch-kos_fibre2$(EXEEXT): 541 @${CXX} ctxswitch/kos_fibre2.cpp -DBENCH_N=50000000 -I. -I/home/tdelisle/software/KOS/src/ -g -O2 -lfibre -lpthread -lrt 529 @@BACKEND_CC@ ctxswitch/pthreads.c -DBENCH_N=50000000 -I. -lrt -pthread ${AM_CFLAGS} ${CFLAGS} ${ccflags} 542 530 543 531 ctxswitch-goroutine$(EXEEXT): … … 694 682 695 683 compile-io$(EXEEXT): 696 @${CC} -quiet -fsyntax-only -w ../tests/io 1.c@CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}684 @${CC} -quiet -fsyntax-only -w ../tests/io.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 697 685 698 686 compile-monitor$(EXEEXT): 699 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}687 @${CC} -quiet -fsyntax-only -w ../tests/concurrent/monitor.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 700 688 701 689 compile-operators$(EXEEXT): … … 706 694 707 695 compile-typeof$(EXEEXT): 708 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags}696 @${CC} -quiet -fsyntax-only -w ../tests/typeof.c @CFA_FLAGS@ ${AM_CFLAGS} ${CFLAGS} ${ccflags} 709 697 710 698 # Tell versions [3.59,3.63) of GNU make to not export all variables. -
src/libcfa/concurrency/invoke.h
radb6a4f1 recae5860 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 19 08:23:21201813 // Update Count : 3 112 // Last Modified On : Fri Mar 30 22:33:59 2018 13 // Update Count : 30 14 14 // 15 15 … … 18 18 #include "bits/locks.h" 19 19 20 #define TL_GET( member ) kernelTLS.member 21 #define TL_SET( member, value ) kernelTLS.member = value; 22 20 23 #ifdef __cforall 21 24 extern "C" { … … 25 28 #ifndef _INVOKE_H_ 26 29 #define _INVOKE_H_ 27 28 #ifdef __ARM_ARCH29 // function prototypes are only really used by these macros on ARM30 void disable_global_interrupts();31 void enable_global_interrupts();32 33 #define TL_GET( member ) ( { __typeof__( kernelTLS.member ) target; \34 disable_global_interrupts(); \35 target = kernelTLS.member; \36 enable_global_interrupts(); \37 target; } )38 #define TL_SET( member, value ) disable_global_interrupts(); \39 kernelTLS.member = value; \40 enable_global_interrupts();41 #else42 #define TL_GET( member ) kernelTLS.member43 #define TL_SET( member, value ) kernelTLS.member = value;44 #endif45 30 46 31 #ifdef __cforall
Note:
See TracChangeset
for help on using the changeset viewer.