| 1 | //
 | 
|---|
| 2 | // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
 | 
|---|
| 3 | //
 | 
|---|
| 4 | // The contents of this file are covered under the licence agreement in the
 | 
|---|
| 5 | // file "LICENCE" distributed with Cforall.
 | 
|---|
| 6 | //
 | 
|---|
| 7 | // Inspect.cpp -- Helpers to get information from the AST.
 | 
|---|
| 8 | //
 | 
|---|
| 9 | // Author           : Thierry Delisle
 | 
|---|
| 10 | // Created On       : Fri Jun 24 13:16:31 2022
 | 
|---|
| 11 | // Last Modified By : Andrew Beach
 | 
|---|
| 12 | // Last Modified On : Fri Apr 14 15:09:00 2023
 | 
|---|
| 13 | // Update Count     : 4
 | 
|---|
| 14 | //
 | 
|---|
| 15 | 
 | 
|---|
| 16 | #include "Inspect.hpp"
 | 
|---|
| 17 | 
 | 
|---|
| 18 | #include <iostream>
 | 
|---|
| 19 | #include <iterator>
 | 
|---|
| 20 | 
 | 
|---|
| 21 | #include "AST/Decl.hpp"
 | 
|---|
| 22 | #include "AST/Expr.hpp"
 | 
|---|
| 23 | #include "AST/Print.hpp"
 | 
|---|
| 24 | #include "AST/Stmt.hpp"
 | 
|---|
| 25 | #include "AST/Type.hpp"
 | 
|---|
| 26 | #include "CodeGen/OperatorTable.hpp"
 | 
|---|
| 27 | 
 | 
|---|
| 28 | namespace ast {
 | 
|---|
| 29 | 
 | 
|---|
| 30 | const Type * getPointerBase( const Type * type ) {
 | 
|---|
| 31 |         if ( const auto * p = dynamic_cast< const PointerType * >( type ) ) {
 | 
|---|
| 32 |                 return p->base;
 | 
|---|
| 33 |         } else if ( auto a = dynamic_cast< const ArrayType * >( type ) ) {
 | 
|---|
| 34 |                 return a->base;
 | 
|---|
| 35 |         } else if ( auto r = dynamic_cast< const ReferenceType * >( type ) ) {
 | 
|---|
| 36 |                 return r->base;
 | 
|---|
| 37 |         } else {
 | 
|---|
| 38 |                 return nullptr;
 | 
|---|
| 39 |         }
 | 
|---|
| 40 | }
 | 
|---|
| 41 | 
 | 
|---|
| 42 | template<typename CallExpr, typename Ret>
 | 
|---|
| 43 | static Ret throughDeref( const CallExpr * expr, Ret(*func)( const Expr * ) ) {
 | 
|---|
| 44 |         // In `(*f)(x)` the function we want is `f`.
 | 
|---|
| 45 |         std::string name = getFunctionName( expr );
 | 
|---|
| 46 |         assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
 | 
|---|
| 47 |         assertf( !expr->args.empty(), "Cannot pass through dereference with no arguments." );
 | 
|---|
| 48 |         return func( expr->args.front() );
 | 
|---|
| 49 | }
 | 
|---|
| 50 | 
 | 
|---|
| 51 | static const DeclWithType * getCalledFunction( const Expr * expr ) {
 | 
|---|
| 52 |         assert( expr );
 | 
|---|
| 53 |         if ( const auto * varExpr = dynamic_cast< const VariableExpr * >( expr ) ) {
 | 
|---|
| 54 |                 return varExpr->var;
 | 
|---|
| 55 |         } else if ( auto memberExpr = dynamic_cast< const MemberExpr * >( expr ) ) {
 | 
|---|
| 56 |                 return memberExpr->member;
 | 
|---|
| 57 |         } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
 | 
|---|
| 58 |                 return getCalledFunction( castExpr->arg );
 | 
|---|
| 59 |         } else if ( auto untypedExpr = dynamic_cast< const UntypedExpr * >( expr ) ) {
 | 
|---|
| 60 |                 return throughDeref( untypedExpr, getCalledFunction );
 | 
|---|
| 61 |         } else if ( auto appExpr = dynamic_cast< const ApplicationExpr * > ( expr ) ) {
 | 
|---|
| 62 |                 return throughDeref( appExpr, getCalledFunction );
 | 
|---|
| 63 |         } else if ( auto addrExpr = dynamic_cast< const AddressExpr * >( expr ) ) {
 | 
|---|
| 64 |                 return getCalledFunction( addrExpr->arg );
 | 
|---|
| 65 |         } else if ( auto commaExpr = dynamic_cast< const CommaExpr * >( expr ) ) {
 | 
|---|
| 66 |                 return getCalledFunction( commaExpr->arg2 );
 | 
|---|
| 67 |         } else {
 | 
|---|
| 68 |                 return nullptr;
 | 
|---|
| 69 |         }
 | 
|---|
| 70 | }
 | 
|---|
| 71 | 
 | 
|---|
| 72 | const DeclWithType * getFunction( const Expr * expr ) {
 | 
|---|
| 73 |         if ( auto app = dynamic_cast< const ApplicationExpr * >( expr ) ) {
 | 
|---|
| 74 |                 return getCalledFunction( app->func );
 | 
|---|
| 75 |         } else if ( auto untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {
 | 
|---|
| 76 |                 return getCalledFunction( untyped->func );
 | 
|---|
| 77 |         } else {
 | 
|---|
| 78 |                 assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
 | 
|---|
| 79 |         }
 | 
|---|
| 80 | }
 | 
|---|
| 81 | 
 | 
|---|
| 82 | // There is a lot of overlap with getCalledFunction. Ideally it would use
 | 
|---|
| 83 | // it as a helper function and return the name of the DeclWithType. But the
 | 
|---|
| 84 | // NameExpr and UntypedMemberExpr only work on this version.
 | 
|---|
| 85 | static std::string funcName( const Expr * func ) {
 | 
|---|
| 86 |         assert( func );
 | 
|---|
| 87 |         if ( const auto * nameExpr = dynamic_cast< const NameExpr * >( func ) ) {
 | 
|---|
| 88 |                 return nameExpr->name;
 | 
|---|
| 89 |         } else if ( auto varExpr = dynamic_cast< const VariableExpr * >( func ) ) {
 | 
|---|
| 90 |                 return varExpr->var->name;
 | 
|---|
| 91 |         } else if ( auto castExpr = dynamic_cast< const CastExpr * >( func ) ) {
 | 
|---|
| 92 |                 return funcName( castExpr->arg );
 | 
|---|
| 93 |         } else if ( auto memberExpr = dynamic_cast< const MemberExpr * >( func ) ) {
 | 
|---|
| 94 |                 return memberExpr->member->name;
 | 
|---|
| 95 |         } else if ( auto memberExpr = dynamic_cast< const UntypedMemberExpr * >( func ) ) {
 | 
|---|
| 96 |                 return funcName( memberExpr->member );
 | 
|---|
| 97 |         } else if ( auto untypedExpr = dynamic_cast< const UntypedExpr * >( func ) ) {
 | 
|---|
| 98 |                 return throughDeref( untypedExpr, funcName );
 | 
|---|
| 99 |         } else if ( auto appExpr = dynamic_cast< const ApplicationExpr * >( func ) ) {
 | 
|---|
| 100 |                 return throughDeref( appExpr, funcName );
 | 
|---|
| 101 |         } else if ( auto ctorExpr = dynamic_cast< const ConstructorExpr * >( func ) ) {
 | 
|---|
| 102 |                 return funcName( getCallArg( ctorExpr->callExpr, 0 ) );
 | 
|---|
| 103 |         } else {
 | 
|---|
| 104 |                 assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
 | 
|---|
| 105 |         }
 | 
|---|
| 106 | }
 | 
|---|
| 107 | 
 | 
|---|
| 108 | std::string getFunctionName( const Expr * expr ) {
 | 
|---|
| 109 |         // There's some unforunate overlap here with getFunction. See above.
 | 
|---|
| 110 |         if ( auto app = dynamic_cast< const ApplicationExpr * >( expr ) ) {
 | 
|---|
| 111 |                 return funcName( app->func );
 | 
|---|
| 112 |         } else if ( auto untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {
 | 
|---|
| 113 |                 return funcName( untyped->func );
 | 
|---|
| 114 |         } else {
 | 
|---|
| 115 |                 assertf( false, "getFunctionName received unknown expression: %s", toString( expr ).c_str() );
 | 
|---|
| 116 |         }
 | 
|---|
| 117 | }
 | 
|---|
| 118 | 
 | 
|---|
| 119 | template<typename CallExpr>
 | 
|---|
| 120 | static const Expr * callArg( const CallExpr * call, unsigned int pos ) {
 | 
|---|
| 121 |         assertf( pos < call->args.size(),
 | 
|---|
| 122 |                 "callArg for argument that doesn't exist: (%u); %s.",
 | 
|---|
| 123 |                 pos, toString( call ).c_str() );
 | 
|---|
| 124 |         auto it = call->args.begin();
 | 
|---|
| 125 |         std::advance( it, pos );
 | 
|---|
| 126 |         return *it;
 | 
|---|
| 127 | }
 | 
|---|
| 128 | 
 | 
|---|
| 129 | const Expr * getCallArg( const Expr * call, unsigned int pos ) {
 | 
|---|
| 130 |         if ( auto app = dynamic_cast< const ApplicationExpr * >( call ) ) {
 | 
|---|
| 131 |                 return callArg( app, pos );
 | 
|---|
| 132 |         } else if ( auto untyped = dynamic_cast< const UntypedExpr * >( call ) ) {
 | 
|---|
| 133 |                 return callArg( untyped, pos );
 | 
|---|
| 134 |         } else if ( auto tupleAssn = dynamic_cast< const TupleAssignExpr * >( call ) ) {
 | 
|---|
| 135 |                 const std::list<ptr<Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids;
 | 
|---|
| 136 |                 assertf( !stmts.empty(), "TupleAssignExpr missing statements." );
 | 
|---|
| 137 |                 auto stmt  = stmts.back().strict_as< ExprStmt >();
 | 
|---|
| 138 |                 auto tuple = stmt->expr.strict_as< TupleExpr >();
 | 
|---|
| 139 |                 assertf( !tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr." );
 | 
|---|
| 140 |                 return getCallArg( tuple->exprs.front(), pos );
 | 
|---|
| 141 |         } else if ( auto ctor = dynamic_cast< const ImplicitCopyCtorExpr * >( call ) ) {
 | 
|---|
| 142 |                 return getCallArg( ctor->callExpr, pos );
 | 
|---|
| 143 |         } else {
 | 
|---|
| 144 |                 assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( call ).c_str() );
 | 
|---|
| 145 |         }
 | 
|---|
| 146 | }
 | 
|---|
| 147 | 
 | 
|---|
| 148 | bool structHasFlexibleArray( const ast::StructDecl * decl ) {
 | 
|---|
| 149 |         if(decl->members.size() == 0) return false;
 | 
|---|
| 150 |         const auto & last = *decl->members.rbegin();
 | 
|---|
| 151 |         auto lastd = last.as<ast::DeclWithType>();
 | 
|---|
| 152 |         // I don't know what this is possible, but it might be.
 | 
|---|
| 153 |         if(!lastd) return false;
 | 
|---|
| 154 |         auto atype = dynamic_cast<const ast::ArrayType *>(lastd->get_type());
 | 
|---|
| 155 |         if(!atype) return false;
 | 
|---|
| 156 |         return !atype->isVarLen && !atype->dimension;
 | 
|---|
| 157 | }
 | 
|---|
| 158 | 
 | 
|---|
| 159 | const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr ) {
 | 
|---|
| 160 |         auto appExpr = dynamic_cast< const ApplicationExpr * >( expr );
 | 
|---|
| 161 |         if ( !appExpr ) return nullptr;
 | 
|---|
| 162 | 
 | 
|---|
| 163 |         const DeclWithType * func = getCalledFunction( appExpr->func );
 | 
|---|
| 164 |         assertf( func, "getCalledFunction returned nullptr: %s",
 | 
|---|
| 165 |                 toString( appExpr->func ).c_str() );
 | 
|---|
| 166 | 
 | 
|---|
| 167 |         return func->linkage == Linkage::Intrinsic ? appExpr : nullptr;
 | 
|---|
| 168 | }
 | 
|---|
| 169 | 
 | 
|---|
| 170 | bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
 | 
|---|
| 171 |         return obj && obj->name.empty() && obj->bitfieldWidth;
 | 
|---|
| 172 | }
 | 
|---|
| 173 | 
 | 
|---|
| 174 | } // namespace ast
 | 
|---|