void ctrl_exception_done(void* desc, void* cpu, integer_t val) { int proc_no = SIM_get_proc_no((conf_object_t*) cpu); conf_object_t* cpu_obj = (conf_object_t*) cpu; uinteger_t trap_level = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tl")); uinteger_t pc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "pc")); uinteger_t npc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "npc")); uinteger_t tpc = 0; uinteger_t tnpc = 0; //get the return PC,NPC pair based on the trap level ASSERT(1 <= trap_level && trap_level <= 5); if(trap_level == 1){ tpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tpc1")); tnpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tnpc1")); } if(trap_level == 2){ tpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tpc2")); tnpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tnpc2")); } if(trap_level == 3){ tpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tpc3")); tnpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tnpc3")); } if(trap_level == 4){ tpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tpc4")); tnpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tnpc4")); } if(trap_level == 5){ tpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tpc5")); tnpc = SIM_read_register(cpu_obj, SIM_get_register_number(cpu_obj, "tnpc5")); } if (!XACT_MEMORY) return; TransactionInterfaceManager *xact_mgr = XACT_MGR; int smt_thread_num = proc_no % RubyConfig::numberofSMTThreads(); // The simulated processor number int sim_proc_no = proc_no / RubyConfig::numberofSMTThreads(); if (proc_no != SIMICS_current_processor_number()){ WARN_EXPR(proc_no); WARN_EXPR(SIMICS_current_processor_number()); WARN_MSG("Callback for a different processor"); } g_system_ptr->getProfiler()->profileExceptionDone(xact_mgr->getTransactionLevel(smt_thread_num) > 0, sim_proc_no, smt_thread_num, val, trap_level, pc, npc, tpc, tnpc); if((val >= 0x80 && val <= 0x9f) || (val >= 0xc0 && val <= 0xdf)){ //xact_mgr->clearLoggedException(smt_thread_num); } if ((val == 0x122) && xact_mgr->shouldTrap(smt_thread_num)){ // use software handler if (xact_mgr->shouldUseHardwareAbort(smt_thread_num)){ xact_mgr->hardwareAbort(smt_thread_num); } else { xact_mgr->trapToHandler(smt_thread_num); } } }
/* Calculate whether an assertion is a standard GObject type check. * .e.g. NSPACE_IS_OBJ(x). * * This is complicated by the fact that type checking is done by macros, which * expand to something like: * (((__extension__ ({ * GTypeInstance *__inst = (GTypeInstance *)((x)); * GType __t = ((nspace_obj_get_type())); * gboolean __r; * if (!__inst) * __r = (0); * else if (__inst->g_class && __inst->g_class->g_type == __t) * __r = (!(0)); * else * __r = g_type_check_instance_is_a(__inst, __t); * __r; * })))) * * Insert the ValueDecls of the variables being checked into the provided * unordered_set, and return the number of such insertions (this will be 0 if no * variables are type checked). The returned number may be an over-estimate * of the number of elements in the set, as it doesn’t account for * duplicates. */ static unsigned int _assertion_is_gobject_type_check (Expr& assertion_expr, const ASTContext& context, std::unordered_set<const ValueDecl*>& ret) { DEBUG_EXPR (__func__ << ": ", assertion_expr); switch ((int) assertion_expr.getStmtClass ()) { case Expr::StmtExprClass: { /* Parse all the way through the statement expression, checking * if the first statement is an assignment to the __inst * variable, as in the macro expansion given above. * * This is a particularly shoddy way of checking for a GObject * type check (we should really check for a * g_type_check_instance_is_a() call) but this will do for * now. */ StmtExpr& stmt_expr = cast<StmtExpr> (assertion_expr); CompoundStmt* compound_stmt = stmt_expr.getSubStmt (); const Stmt* first_stmt = *(compound_stmt->body_begin ()); if (first_stmt->getStmtClass () != Expr::DeclStmtClass) return 0; const DeclStmt& decl_stmt = cast<DeclStmt> (*first_stmt); const VarDecl* decl = dyn_cast<VarDecl> (decl_stmt.getSingleDecl ()); if (decl == NULL) return 0; if (decl->getNameAsString () != "__inst") return 0; const Expr* init = decl->getAnyInitializer ()->IgnoreParenCasts (); const DeclRefExpr* decl_expr = dyn_cast<DeclRefExpr> (init); if (decl_expr != NULL) { ret.insert (decl_expr->getDecl ()); return 1; } return 0; } case Expr::IntegerLiteralClass: case Expr::BinaryOperatorClass: case Expr::UnaryOperatorClass: case Expr::ConditionalOperatorClass: case Expr::CallExprClass: case Expr::ImplicitCastExprClass: { /* These can’t be type checks. */ return 0; } case Stmt::StmtClass::NoStmtClass: default: WARN_EXPR (__func__ << "() can’t handle expressions of type " << assertion_expr.getStmtClassName (), assertion_expr); return 0; } }
void Tester::checkForDeadlock() { int size = m_last_progress_vector.size(); Time current_time = g_eventQueue_ptr->getTime(); for (int processor=0; processor<size; processor++) { if ((current_time - m_last_progress_vector[processor]) > g_DEADLOCK_THRESHOLD) { WARN_EXPR(current_time); WARN_EXPR(m_last_progress_vector[processor]); WARN_EXPR(current_time - m_last_progress_vector[processor]); WARN_EXPR(processor); Sequencer* seq_ptr = g_system_ptr->getChip(processor/RubyConfig::numberOfProcsPerChip())->getSequencer(processor%RubyConfig::numberOfProcsPerChip()); assert(seq_ptr != NULL); WARN_EXPR(*seq_ptr); #ifdef USE_TOPAZ cerr<<"******TOPAZ POST DEADLOCK STATS************"<<endl; g_system_ptr->getNetwork()->printStats(cerr); #endif ERROR_MSG("Deadlock detected."); } } }
void RequestGenerator::wakeup() { DEBUG_EXPR(TESTER_COMP, MedPrio, m_node); DEBUG_EXPR(TESTER_COMP, MedPrio, m_status); if (m_status == RequestGeneratorStatus_Thinking) { m_status = RequestGeneratorStatus_Test_Pending; m_last_transition = g_eventQueue_ptr->getTime(); initiateTest(); // Test } else if (m_status == RequestGeneratorStatus_Holding) { m_status = RequestGeneratorStatus_Release_Pending; m_last_transition = g_eventQueue_ptr->getTime(); initiateRelease(); // Release } else if (m_status == RequestGeneratorStatus_Before_Swap) { m_status = RequestGeneratorStatus_Swap_Pending; m_last_transition = g_eventQueue_ptr->getTime(); initiateSwap(); } else { WARN_EXPR(m_status); ERROR_MSG("Invalid status"); } }
void Check::performCallback(NodeID proc, SubBlock& data) { Address address = data.getAddress(); // assert(getAddress() == address); // This isn't exactly right since we now have multi-byte checks assert(getAddress().getLineAddress() == address.getLineAddress()); DEBUG_MSG(TESTER_COMP, MedPrio, "Callback"); DEBUG_EXPR(TESTER_COMP, MedPrio, *this); if (m_status == TesterStatus_Action_Pending) { DEBUG_MSG(TESTER_COMP, MedPrio, "Action callback"); // Perform store data.setByte(0, m_value+m_store_count); // We store one byte at a time m_store_count++; if (m_store_count == CHECK_SIZE) { m_status = TesterStatus_Ready; } else { m_status = TesterStatus_Idle; } } else if (m_status == TesterStatus_Check_Pending) { DEBUG_MSG(TESTER_COMP, MedPrio, "Check callback"); // Perform load/check for(int byte_number=0; byte_number<CHECK_SIZE; byte_number++) { if (uint8(m_value+byte_number) != data.getByte(byte_number) && (DATA_BLOCK == true)) { WARN_EXPR(proc); WARN_EXPR(address); WARN_EXPR(data); WARN_EXPR(byte_number); WARN_EXPR((int)m_value+byte_number); WARN_EXPR((int)data.getByte(byte_number)); WARN_EXPR(*this); WARN_EXPR(g_eventQueue_ptr->getTime()); ERROR_MSG("Action/check failure"); } } DEBUG_MSG(TESTER_COMP, HighPrio, "Action/check success:"); DEBUG_EXPR(TESTER_COMP, HighPrio, *this); DEBUG_EXPR(TESTER_COMP, MedPrio, data); m_status = TesterStatus_Idle; pickValue(); } else { WARN_EXPR(*this); WARN_EXPR(proc); WARN_EXPR(data); WARN_EXPR(m_status); WARN_EXPR(g_eventQueue_ptr->getTime()); ERROR_MSG("Unexpected TesterStatus"); } DEBUG_EXPR(TESTER_COMP, MedPrio, proc); DEBUG_EXPR(TESTER_COMP, MedPrio, data); DEBUG_EXPR(TESTER_COMP, MedPrio, getAddress().getLineAddress()); DEBUG_MSG(TESTER_COMP, MedPrio, "Callback done"); DEBUG_EXPR(TESTER_COMP, MedPrio, *this); }
/* Calculate whether an assertion is a standard non-NULL check. * e.g. (x != NULL), (x), (x != NULL && …) or (x && …). * * Insert the ValueDecls of the variables being checked into the provided * unordered_set, and return the number of such insertions (this will be 0 if no * variables are non-NULL checked). The returned number may be an over-estimate * of the number of elements in the set, as it doesn’t account for * duplicates. */ static unsigned int _assertion_is_explicit_nonnull_check (Expr& assertion_expr, const ASTContext& context, std::unordered_set<const ValueDecl*>& ret) { DEBUG_EXPR (__func__ << ": ", assertion_expr); switch ((int) assertion_expr.getStmtClass ()) { case Expr::BinaryOperatorClass: { BinaryOperator& bin_expr = cast<BinaryOperator> (assertion_expr); BinaryOperatorKind opcode = bin_expr.getOpcode (); if (opcode == BinaryOperatorKind::BO_LAnd) { /* LHS && RHS */ unsigned int lhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getLHS ()), context, ret); unsigned int rhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getRHS ()), context, ret); return lhs_count + rhs_count; } else if (opcode == BinaryOperatorKind::BO_LOr) { /* LHS || RHS */ std::unordered_set<const ValueDecl*> lhs_vars, rhs_vars; unsigned int lhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getLHS ()), context, lhs_vars); unsigned int rhs_count = AssertionExtracter::assertion_is_nonnull_check (*(bin_expr.getRHS ()), context, rhs_vars); std::set_intersection (lhs_vars.begin (), lhs_vars.end (), rhs_vars.begin (), rhs_vars.end (), std::inserter (ret, ret.end ())); return lhs_count + rhs_count; } else if (opcode == BinaryOperatorKind::BO_NE) { /* LHS != RHS */ Expr* rhs = bin_expr.getRHS (); Expr::NullPointerConstantKind k = rhs->isNullPointerConstant (const_cast<ASTContext&> (context), Expr::NullPointerConstantValueDependence::NPC_ValueDependentIsNotNull); if (k != Expr::NullPointerConstantKind::NPCK_NotNull && bin_expr.getLHS ()->IgnoreParenCasts ()->getStmtClass () == Expr::DeclRefExprClass) { DEBUG ("Found non-NULL check."); ret.insert (cast<DeclRefExpr> (bin_expr.getLHS ()->IgnoreParenCasts ())->getDecl ()); return 1; } /* Either not a comparison to NULL, or the expr being * compared is not a DeclRefExpr. */ return 0; } return 0; } case Expr::UnaryOperatorClass: { /* A unary operator. For the moment, assume this isn't a * non-null check. * * FIXME: In the future, define a proper program transformation * to check for non-null checks, since we could have expressions * like: * !(my_var == NULL) * or (more weirdly): * ~(my_var == NULL) */ return 0; } case Expr::ConditionalOperatorClass: { /* A conditional operator. For the moment, assume this isn’t a * non-null check. * * FIXME: In the future, define a proper program transformation * to check for non-null checks, since we could have expressions * like: * (x == NULL) ? TRUE : FALSE */ return 0; } case Expr::CStyleCastExprClass: case Expr::ImplicitCastExprClass: { /* A (explicit or implicit) cast. This can either be: * (void*)0 * or * (bool)my_var */ CastExpr& cast_expr = cast<CastExpr> (assertion_expr); Expr* sub_expr = cast_expr.getSubExpr ()->IgnoreParenCasts (); if (sub_expr->getStmtClass () == Expr::DeclRefExprClass) { DEBUG ("Found non-NULL check."); ret.insert (cast<DeclRefExpr> (sub_expr)->getDecl ()); return 1; } /* Not a cast to NULL, or the expr being casted is not a * DeclRefExpr. */ return 0; } case Expr::DeclRefExprClass: { /* A variable reference, which will implicitly become a non-NULL * check. */ DEBUG ("Found non-NULL check."); DeclRefExpr& decl_ref_expr = cast<DeclRefExpr> (assertion_expr); ret.insert (decl_ref_expr.getDecl ()); return 1; } case Expr::StmtExprClass: /* FIXME: Statement expressions can be nonnull checks, but * detecting them requires a formal program transformation which * has not been implemented yet. */ case Expr::CallExprClass: /* Function calls can’t be nonnull checks. */ case Expr::IntegerLiteralClass: { /* Integer literals can’t be nonnull checks. */ return 0; } case Stmt::StmtClass::NoStmtClass: default: WARN_EXPR (__func__ << "() can’t handle expressions of type " << assertion_expr.getStmtClassName (), assertion_expr); return 0; } }
/* Does the given statement look like: * • g_return_if_fail(…) * • g_return_val_if_fail(…) * • g_assert(…) * • g_assert_*(…) * • assert(…) * This is complicated by the fact that if the gmessages.h header isn’t * available, they’ll present as CallExpr function calls with those names; if it * is available, they’ll be expanded as macros and turn into DoStmts with misc. * rubbish beneath. * * If the statement changes program state at all, return NULL. Otherwise, return * the condition which holds for the assertion to be bypassed (i.e. for the * assertion to succeed). This function is built recursively, building a boolean * expression for the condition based on avoiding branches which call * abort()-like functions. * * This function is based on a transformation of the AST to an augmented boolean * expression, using rules documented in each switch case. In this * documentation, calc(S) refers to the transformation function. The augmented * boolean expressions can be either NULL, or a normal boolean expression * (TRUE, FALSE, ∧, ∨, ¬). NULL is used iff the statement potentially changes * program state, and poisons any boolean expression: * B ∧ NULL ≡ NULL * B ∨ NULL ≡ NULL * ¬NULL ≡ NULL */ Expr* AssertionExtracter::is_assertion_stmt (Stmt& stmt, const ASTContext& context) { DEBUG ("Checking " << stmt.getStmtClassName () << " for assertions."); /* Slow path: walk through the AST, aborting on statements which * potentially mutate program state, and otherwise trying to find a base * function call such as: * • g_return_if_fail_warning() * • g_assertion_message() * • g_assertion_message_*() */ switch ((int) stmt.getStmtClass ()) { case Stmt::StmtClass::CallExprClass: { /* Handle a direct function call. * Transformations: * [g_return_if_fail|assert|…](C) ↦ C * [g_return_if_fail_warning|__assert_fail|…](C) ↦ FALSE * other_funcs(…) ↦ NULL */ CallExpr& call_expr = cast<CallExpr> (stmt); FunctionDecl* func = call_expr.getDirectCallee (); if (func == NULL) return NULL; std::string func_name = func->getNameAsString (); DEBUG ("CallExpr to function " << func_name); if (_is_assertion_name (func_name)) { /* Assertion path where the compiler hasn't seen the * definition of the assertion macro, so still thinks * it's a function. * * Extract the assertion condition as the first function * parameter. * * TODO: May need to fix up the condition for macros * like g_assert_null(). */ return call_expr.getArg (0); } else if (_is_assertion_fail_func_name (func_name)) { /* Assertion path where the assertion macro has been * expanded and we're on the assertion failure branch. * * In this case, the assertion condition has been * grabbed from an if statement already, so negate it * (to avoid the failure condition) and return. */ return new (context) IntegerLiteral (context, context.MakeIntValue (0, context.getLogicalOperationType ()), context.getLogicalOperationType (), SourceLocation ()); } /* Not an assertion path. */ return NULL; } case Stmt::StmtClass::DoStmtClass: { /* Handle a do { … } while (0) block (commonly used to allow * macros to optionally be suffixed by a semicolon). * Transformations: * do { S } while (0) ↦ calc(S) * do { S } while (C) ↦ NULL * Note the second condition is overly-conservative. No * solutions for the halting problem here. */ DoStmt& do_stmt = cast<DoStmt> (stmt); Stmt* body = do_stmt.getBody (); Stmt* cond = do_stmt.getCond (); Expr* expr = dyn_cast<Expr> (cond); llvm::APSInt bool_expr; if (body != NULL && expr != NULL && expr->isIntegerConstantExpr (bool_expr, context) && !bool_expr.getBoolValue ()) { return is_assertion_stmt (*body, context); } return NULL; } case Stmt::StmtClass::IfStmtClass: { /* Handle an if(…) { … } else { … } block. * Transformations: * if (C) { S1 } else { S2 } ↦ * (C ∧ calc(S1)) ∨ (¬C ∧ calc(S2)) * if (C) { S } ↦ (C ∧ calc(S)) ∨ ¬C * i.e. * if (C) { S } ≡ if (C) { S } else {} * where {} is an empty compound statement, below. */ IfStmt& if_stmt = cast<IfStmt> (stmt); assert (if_stmt.getThen () != NULL); Expr* neg_cond = _negation_expr (if_stmt.getCond (), context); Expr* then_assertion = is_assertion_stmt (*(if_stmt.getThen ()), context); if (then_assertion == NULL) return NULL; then_assertion = _conjunction_expr (if_stmt.getCond (), then_assertion, context); if (if_stmt.getElse () == NULL) return _disjunction_expr (then_assertion, neg_cond, context); Expr* else_assertion = is_assertion_stmt (*(if_stmt.getElse ()), context); if (else_assertion == NULL) return NULL; else_assertion = _conjunction_expr (neg_cond, else_assertion, context); return _disjunction_expr (then_assertion, else_assertion, context); } case Stmt::StmtClass::ConditionalOperatorClass: { /* Handle a ternary operator. * Transformations: * C ? S1 : S2 ↦ * (C ∧ calc(S1)) ∨ (¬C ∧ calc(S2)) */ ConditionalOperator& op_expr = cast<ConditionalOperator> (stmt); assert (op_expr.getTrueExpr () != NULL); assert (op_expr.getFalseExpr () != NULL); Expr* neg_cond = _negation_expr (op_expr.getCond (), context); Expr* then_assertion = is_assertion_stmt (*(op_expr.getTrueExpr ()), context); if (then_assertion == NULL) return NULL; then_assertion = _conjunction_expr (op_expr.getCond (), then_assertion, context); Expr* else_assertion = is_assertion_stmt (*(op_expr.getFalseExpr ()), context); if (else_assertion == NULL) return NULL; else_assertion = _conjunction_expr (neg_cond, else_assertion, context); return _disjunction_expr (then_assertion, else_assertion, context); } case Stmt::StmtClass::SwitchStmtClass: { /* Handle a switch statement. * Transformations: * switch (C) { L1: S1; L2: S2; …; Lz: Sz } ↦ NULL * FIXME: This should get a proper transformation sometime. */ return NULL; } case Stmt::StmtClass::AttributedStmtClass: { /* Handle an attributed statement, e.g. G_LIKELY(…). * Transformations: * att S ↦ calc(S) */ AttributedStmt& attr_stmt = cast<AttributedStmt> (stmt); Stmt* sub_stmt = attr_stmt.getSubStmt (); if (sub_stmt == NULL) return NULL; return is_assertion_stmt (*sub_stmt, context); } case Stmt::StmtClass::CompoundStmtClass: { /* Handle a compound statement, e.g. { stmt1; stmt2; }. * Transformations: * S1; S2; …; Sz ↦ calc(S1) ∧ calc(S2) ∧ … ∧ calc(Sz) * {} ↦ TRUE * * This is implemented by starting with a base TRUE case in the * compound_condition, then taking the conjunction with the next * statement’s assertion condition for each statement in the * compound. * * If the compound is empty, the compound_condition will be * TRUE. Otherwise, it will be (TRUE ∧ …), which will be * simplified later. */ CompoundStmt& compound_stmt = cast<CompoundStmt> (stmt); Expr* compound_condition = new (context) IntegerLiteral (context, context.MakeIntValue (1, context.getLogicalOperationType ()), context.getLogicalOperationType (), SourceLocation ()); for (CompoundStmt::const_body_iterator it = compound_stmt.body_begin (), ie = compound_stmt.body_end (); it != ie; ++it) { Stmt* body_stmt = *it; Expr* body_assertion = is_assertion_stmt (*body_stmt, context); if (body_assertion == NULL) { /* Reached a program state mutation. */ return NULL; } /* Update the compound condition. */ compound_condition = _conjunction_expr (compound_condition, body_assertion, context); DEBUG_EXPR ("Compound condition: ", *compound_condition); } return compound_condition; } case Stmt::StmtClass::GotoStmtClass: /* Handle a goto statement. * Transformations: * goto L ↦ FALSE */ case Stmt::StmtClass::ReturnStmtClass: { /* Handle a return statement. * Transformations: * return ↦ FALSE */ return new (context) IntegerLiteral (context, context.MakeIntValue (0, context.getLogicalOperationType ()), context.getLogicalOperationType (), SourceLocation ()); } case Stmt::StmtClass::NullStmtClass: /* Handle a null statement. * Transformations: * ; ↦ TRUE */ case Stmt::StmtClass::DeclRefExprClass: /* Handle a variable reference expression. These don’t modify * program state. * Transformations: * E ↦ TRUE */ case Stmt::StmtClass::DeclStmtClass: { /* Handle a variable declaration statement. These don’t modify * program state; they only introduce new state, so can’t affect * subsequent assertions. (FIXME: For the moment, we ignore the * possibility of the rvalue modifying program state.) * Transformations: * T S1 ↦ TRUE * T S1 = S2 ↦ TRUE */ return new (context) IntegerLiteral (context, context.MakeIntValue (1, context.getLogicalOperationType ()), context.getLogicalOperationType (), SourceLocation ()); } case Stmt::StmtClass::IntegerLiteralClass: { /* Handle an integer literal. This doesn’t modify program state, * and evaluates directly to a boolean. * Transformations: * 0 ↦ FALSE * I ↦ TRUE */ return dyn_cast<Expr> (&stmt); } case Stmt::StmtClass::ParenExprClass: { /* Handle a parenthesised expression. * Transformations: * ( S ) ↦ calc(S) */ ParenExpr& paren_expr = cast<ParenExpr> (stmt); Stmt* sub_expr = paren_expr.getSubExpr (); if (sub_expr == NULL) return NULL; return is_assertion_stmt (*sub_expr, context); } case Stmt::StmtClass::LabelStmtClass: { /* Handle a label statement. * Transformations: * label: S ↦ calc(S) */ LabelStmt& label_stmt = cast<LabelStmt> (stmt); Stmt* sub_stmt = label_stmt.getSubStmt (); if (sub_stmt == NULL) return NULL; return is_assertion_stmt (*sub_stmt, context); } case Stmt::StmtClass::ImplicitCastExprClass: case Stmt::StmtClass::CStyleCastExprClass: { /* Handle an explicit or implicit cast. * Transformations: * (T) S ↦ calc(S) */ CastExpr& cast_expr = cast<CastExpr> (stmt); Stmt* sub_expr = cast_expr.getSubExpr (); if (sub_expr == NULL) return NULL; return is_assertion_stmt (*sub_expr, context); } case Stmt::StmtClass::GCCAsmStmtClass: case Stmt::StmtClass::MSAsmStmtClass: /* Inline assembly. There is no way we are parsing this, so * conservatively assume it modifies program state. * Transformations: * A ↦ NULL */ case Stmt::StmtClass::BinaryOperatorClass: /* Handle a binary operator statement. Since this is being * processed at the top level, it’s most likely an assignment, * so conservatively assume it modifies program state. * Transformations: * S1 op S2 ↦ NULL */ case Stmt::StmtClass::UnaryOperatorClass: /* Handle a unary operator statement. Since this is being * processed at the top level, it’s not very interesting re. * assertions, even though it probably won’t modify program * state (unless it’s a pre- or post-increment or -decrement * operator). Be conservative and assume it does, though. * Transformations: * op S ↦ NULL */ case Stmt::StmtClass::CompoundAssignOperatorClass: /* Handle a compound assignment operator, e.g. x += 5. This * definitely modifies program state, so ignore it. * Transformations: * S1 op S2 ↦ NULL */ case Stmt::StmtClass::ForStmtClass: /* Handle a for statement. We assume these *always* change * program state. * Transformations: * for (…) { … } ↦ NULL */ case Stmt::StmtClass::WhileStmtClass: { /* Handle a while(…) { … } block. Because we don't want to solve * the halting problem, just assume all while statements cannot * be assertion statements. * Transformations: * while (C) { S } ↦ NULL */ return NULL; } case Stmt::StmtClass::NoStmtClass: default: WARN_EXPR (__func__ << "() can’t handle statements of type " << stmt.getStmtClassName (), stmt); return NULL; } }
// This code will check for cases if the given cache block is exclusive in // one node and shared in another-- a coherence violation // // To use, the SLICC specification must call sequencer.checkCoherence(address) // when the controller changes to a state with new permissions. Do this // in setState. The SLICC spec must also define methods "isBlockShared" // and "isBlockExclusive" that are specific to that protocol // void System::checkGlobalCoherenceInvariant(const Address& addr ) { NodeID exclusive = -1; bool sharedDetected = false; NodeID lastShared = -1; for (int i = 0; i < m_chip_vector.size(); i++) { if (m_chip_vector[i]->isBlockExclusive(addr)) { if (exclusive != -1) { // coherence violation WARN_EXPR(exclusive); WARN_EXPR(m_chip_vector[i]->getID()); WARN_EXPR(addr); WARN_EXPR(g_eventQueue_ptr->getTime()); ERROR_MSG("Coherence Violation Detected -- 2 exclusive chips"); } else if (sharedDetected) { WARN_EXPR(lastShared); WARN_EXPR(m_chip_vector[i]->getID()); WARN_EXPR(addr); WARN_EXPR(g_eventQueue_ptr->getTime()); ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared"); } else { exclusive = m_chip_vector[i]->getID(); } } else if (m_chip_vector[i]->isBlockShared(addr)) { sharedDetected = true; lastShared = m_chip_vector[i]->getID(); if (exclusive != -1) { WARN_EXPR(lastShared); WARN_EXPR(exclusive); WARN_EXPR(addr); WARN_EXPR(g_eventQueue_ptr->getTime()); ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared"); } } } }
void RequestGenerator::performCallback(NodeID proc, SubBlock& data) { Address address = data.getAddress(); assert(proc == m_node); assert(address == m_address); DEBUG_EXPR(TESTER_COMP, LowPrio, proc); DEBUG_EXPR(TESTER_COMP, LowPrio, m_status); DEBUG_EXPR(TESTER_COMP, LowPrio, address); DEBUG_EXPR(TESTER_COMP, LowPrio, data); if (m_status == RequestGeneratorStatus_Test_Pending) { // m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition); if (data.readByte() == LockStatus_Locked) { // Locked - keep spinning m_status = RequestGeneratorStatus_Thinking; m_last_transition = g_eventQueue_ptr->getTime(); g_eventQueue_ptr->scheduleEvent(this, waitTime()); } else { // Unlocked - try the swap m_driver.recordTestLatency(g_eventQueue_ptr->getTime() - m_last_transition); m_status = RequestGeneratorStatus_Before_Swap; m_last_transition = g_eventQueue_ptr->getTime(); g_eventQueue_ptr->scheduleEvent(this, waitTime()); } } else if (m_status == RequestGeneratorStatus_Swap_Pending) { m_driver.recordSwapLatency(g_eventQueue_ptr->getTime() - m_last_transition); if (data.readByte() == LockStatus_Locked) { // We failed to aquire the lock m_status = RequestGeneratorStatus_Thinking; m_last_transition = g_eventQueue_ptr->getTime(); g_eventQueue_ptr->scheduleEvent(this, waitTime()); } else { // We acquired the lock data.writeByte(LockStatus_Locked); m_status = RequestGeneratorStatus_Holding; m_last_transition = g_eventQueue_ptr->getTime(); DEBUG_MSG(TESTER_COMP, HighPrio, "Acquired"); DEBUG_EXPR(TESTER_COMP, HighPrio, proc); DEBUG_EXPR(TESTER_COMP, HighPrio, g_eventQueue_ptr->getTime()); g_eventQueue_ptr->scheduleEvent(this, holdTime()); } } else if (m_status == RequestGeneratorStatus_Release_Pending) { m_driver.recordReleaseLatency(g_eventQueue_ptr->getTime() - m_last_transition); // We're releasing the lock data.writeByte(LockStatus_Unlocked); m_counter++; if (m_counter < g_param_ptr->TESTER_LENGTH()) { m_status = RequestGeneratorStatus_Thinking; m_last_transition = g_eventQueue_ptr->getTime(); pickAddress(); g_eventQueue_ptr->scheduleEvent(this, thinkTime()); } else { m_driver.reportDone(); m_status = RequestGeneratorStatus_Done; m_last_transition = g_eventQueue_ptr->getTime(); } } else { WARN_EXPR(m_status); ERROR_MSG("Invalid status"); } }