void IntraAnalysisResultsToDotFiles::runAnalysis()
 {
   set<FunctionState*> allFuncs = FunctionState::getAllDefinedFuncs();
   // Go through functions one by one, call an intra-procedural analysis on each of them
   // iterate over all functions with bodies
   for(set<FunctionState*>::iterator it=allFuncs.begin(); it!=allFuncs.end(); it++)
   {
 
     FunctionState* fState = *it;
     // compose the output file name as filename_mangled_function_name.dot
     Function *func = & (fState->getFunc());
     assert (func != NULL);
     SgFunctionDefinition* proc = func->get_definition();
     string file_name = StringUtility::stripPathFromFileName(proc->get_file_info()->get_filename());
     string file_func_name= file_name+ "_"+proc->get_mangled_name().getString();
 
     string full_output = file_func_name +"_cfg.dot";
     std::ofstream ostr(full_output.c_str());
 
     ostr << "digraph " << "mygraph" << " {\n";
     analysisStatesToDOT* dot_analysis = dynamic_cast <analysisStatesToDOT*> ( intraAnalysis);
     assert (dot_analysis != NULL);
     dot_analysis->ostr = &ostr;
     dot_analysis->runAnalysis(fState->func, &(fState->state));
     ostr << "}\n";
   }
 
 }
Esempio n. 2
0
bool gmCodeGenPrivate::GenStmtForEach(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  unsigned int breakAddress, continueAddress, loc1, loc2;

  // Generate table
  if(!Generate(a_node->m_children[0], a_byteCode))
  {
    return false;
  }

  PushLoop();

  // Push the first iterator
  a_byteCode->Emit(BC_PUSHINT, (gmuint32) -2); // first iterator value.

  continueAddress = a_byteCode->Tell();

  // Generate call
  const char * keyVar = s_tempVarName1;
  if(a_node->m_children[2]) keyVar = a_node->m_children[2]->m_data.m_string;
  const char * valueVar = a_node->m_children[1]->m_data.m_string;

  gmuint16 keyOffset = (gmuint16) m_currentFunction->SetVariableType(keyVar, CTVT_LOCAL);
  gmuint16 valueOffset = (gmuint16) m_currentFunction->SetVariableType(valueVar, CTVT_LOCAL);
  gmuint32 opcode = (keyOffset << 16) | (valueOffset & 0xffff);

  loc1 = a_byteCode->Tell();
  a_byteCode->Emit(BC_FOREACH, opcode);

  // Skip space for jump
  loc2 = a_byteCode->Skip(SIZEOF_BC_BRA);

  // Generate body
  if(!Generate(a_node->m_children[3], a_byteCode))
  {
    PopLoop();
    return false;
  }

  a_byteCode->EmitPtr(BC_BRA, (gmuint32) loc1);
  breakAddress = a_byteCode->Seek(loc2);
  a_byteCode->EmitPtr(BC_BRZ, breakAddress);
  a_byteCode->Seek(breakAddress);

  // pop table and iterator
  a_byteCode->Emit(BC_POP2);

  ApplyPatches(m_loopStack[m_currentLoop].m_breaks, a_byteCode, breakAddress);
  ApplyPatches(m_loopStack[m_currentLoop].m_continues, a_byteCode, continueAddress);

  PopLoop();
  return true;
}
Esempio n. 3
0
bool gmCodeGenPrivate::GenStmtFork(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
   GM_ASSERT(a_node->m_type == CTNT_STATEMENT && a_node->m_subType == CTNST_FORK );
   
   gmuint32 loc1,loc2;

   // create the var for the thread id
   const char * valname = 0;
   gmuint32 valref = 0;
   if ( a_node->m_children[1])
   {
      valname = a_node->m_children[1]->m_data.m_string;
      valref = m_currentFunction->SetVariableType( valname, CTVT_LOCAL );
   }

   loc1 = a_byteCode->Skip( SIZEOF_BC_BRA );
   
   if (!valname) a_byteCode->Emit( BC_POP );   // if not specified then just pop
   else a_byteCode->Emit( BC_SETLOCAL, valref );   // store the thread id
   if (!Generate(a_node->m_children[0], a_byteCode )) return false;
   a_byteCode->Emit( BC_RET );
   
   loc2 = a_byteCode->Seek( loc1 );
   a_byteCode->Emit( BC_FORK, loc2 );
   a_byteCode->Seek( loc2 );
   
   if (!valname) a_byteCode->Emit( BC_POP );   // if not specified then just pop
   else a_byteCode->Emit( BC_SETLOCAL, valref );   // store the thread id
   
   return true;
}
Esempio n. 4
0
bool gmCodeGenPrivate::GenDeclVariable(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_DECLARATION && a_node->m_subType == CTNDT_VARIABLE);
  GM_ASSERT(m_currentFunction);
  m_currentFunction->SetVariableType(a_node->m_children[0]->m_data.m_string, (gmCodeTreeVariableType) a_node->m_subTypeType);
  return true;
}
Esempio n. 5
0
gmCodeGenPrivate::FunctionState * gmCodeGenPrivate::PopFunction()
{
  if(m_currentFunction)
  {
    m_currentFunction->Reset();
    m_currentFunction = m_functionStack.GetPrev(m_currentFunction);
    if(!m_functionStack.IsValid(m_currentFunction))
    {
      m_currentFunction = NULL;
    }
  }

  return m_currentFunction;
}
Esempio n. 6
0
    void InterpreterThread::setState(ByteInputStream& stream) {
        functionStackLimit = stream.getUInt32();

        uint64_t stackSize = stream.getUInt64();

        for (std::uint64_t i = 0; i < stackSize; i++) {
            FunctionState functionState;
            functionState.setState(stream);
        }

        uint64_t instructionStackSize = stream.getUInt64();
        instructionStack_.resize(instructionStackSize);
        for (uint64_t i = 0; i < instructionStackSize; i++) {
            instructionStack_.at(i).setThread(*this);
            instructionStack_.at(i).setState(stream, env_);
        }

        uint64_t numberOfHeaps = stream.getUInt64();
        for (uint64_t i = 0; i < numberOfHeaps; i++) {
            std::string moduleName = stream.getString();
            Heap& heap = heapsByModuleName_[moduleName] = Heap();
            heap.setState(stream);
        }
    }
Esempio n. 7
0
gmCodeGenPrivate::FunctionState * gmCodeGenPrivate::PushFunction()
{
  if(m_currentFunction)
  {
    if(m_currentFunction != m_functionStack.GetLast())
    {
      m_currentFunction = m_functionStack.GetNext(m_currentFunction);
    }
    else
    {
      m_currentFunction = GM_NEW( FunctionState() );
      m_functionStack.InsertLast(m_currentFunction);
    }
  }
  else
  {
    if(m_functionStack.IsEmpty())
    {
      m_currentFunction = GM_NEW( FunctionState() );
      m_functionStack.InsertLast(m_currentFunction);
    }
    else
    {
      m_currentFunction = m_functionStack.GetFirst();
    }  
  }

  m_currentFunction->Reset();

  m_currentFunction->m_byteCode.SetSwapEndianOnWrite(m_hooks->SwapEndian());

  // if we are debugging, set up some line number debugging.
  if(m_debug)
  {
    m_currentFunction->m_byteCode.m_emitCallback = gmLineNumberCallback;
  }

  return m_currentFunction;
}
Esempio n. 8
0
bool gmCodeGenPrivate::GenExprIdentifier(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_IDENTIFIER);

  // if local, get local regardless
  // if member, get this
  // if global, get global
  // get global

  if((a_node->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0)
  {
    return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string));
  }

  gmCodeTreeVariableType type;
  int offset = m_currentFunction->GetVariableOffset(a_node->m_data.m_string, type);

  if(offset >= 0 && type == CTVT_LOCAL)
  {
    return a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset);
  }
  else if(offset != -2)
  {
    if(type == CTVT_MEMBER)
    {
      return a_byteCode->EmitPtr(BC_GETTHIS, m_hooks->GetSymbolId(a_node->m_data.m_string));
    }
    else if(type == CTVT_GLOBAL)
    {
      return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string));
    }
    if(m_log) m_log->LogEntry("internal error");
    return false;
  }

  return a_byteCode->EmitPtr(BC_GETGLOBAL, m_hooks->GetSymbolId(a_node->m_data.m_string));
}
Esempio n. 9
0
bool gmCodeGenPrivate::GenExprFunction(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_FUNCTION);

  gmptr id = m_hooks->GetFunctionId();
  a_byteCode->EmitPtr(BC_PUSHFN, id);

  // Create the function
  PushFunction();

  // Get a debug function name as the name of the variable the function is assigned to
  if(m_debug && a_node->m_parent && a_node->m_parent->m_type == CTNT_EXPRESSION && a_node->m_parent->m_subType == CTNET_OPERATION &&
     (a_node->m_parent->m_subTypeType == CTNOT_ASSIGN || a_node->m_parent->m_subTypeType == CTNOT_ASSIGN_FIELD) && a_node->m_parent->m_children[1] == a_node)
  {
    const gmCodeTreeNode * debugName = a_node->m_parent->m_children[0];
    if(debugName && debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER)
    {
    }
    else if(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_OPERATION && 
            debugName->m_subTypeType == CTNOT_DOT)
    {
      debugName = debugName->m_children[1];
    }
    else
    {
      debugName = NULL;
    }

    if(debugName)
    {
      GM_ASSERT(debugName->m_type == CTNT_EXPRESSION && debugName->m_subType == CTNET_IDENTIFIER);
      m_currentFunction->m_debugName = debugName->m_data.m_string;
    }
  }

  // Parameters
  const gmCodeTreeNode * params = a_node->m_children[0];
  int numParams = 0;
  while(params)
  {
    const gmCodeTreeNode * param = params->m_children[0];
    GM_ASSERT(param->m_type == CTNT_EXPRESSION && param->m_subType == CTNET_IDENTIFIER);
    if(m_currentFunction->SetVariableType(param->m_data.m_string, CTVT_LOCAL) != numParams)
    {
      if(m_log) m_log->LogEntry("error (%d) parameter %s already declared", param->m_lineNumber, param->m_data.m_string);
      PopFunction();
      return false;
    }
    ++numParams;
    params = params->m_sibling;
  }

  // Generate the code
  bool res = Generate(a_node->m_children[1], &m_currentFunction->m_byteCode);

  // Generate a return incase the function didnt have one.
  m_currentFunction->m_byteCode.Emit(BC_RET);

  if(res)
  {
    // Create a locals table
    const char ** locals = NULL;
    if(m_debug)
    {
      locals = (const char **) alloca(sizeof(const char *) * m_currentFunction->m_numLocals);
      memset(locals, 0, sizeof(const char *) * m_currentFunction->m_numLocals);

      for(gmuint v = 0; v < m_currentFunction->m_variables.Count(); ++v)
      {
        Variable &variable = m_currentFunction->m_variables[v];
        if(variable.m_offset != -1)
        {
          locals[variable.m_offset] = variable.m_symbol;
        }
      }
    }

    // Add the function to the hooks.

    gmSortDebugLines(m_currentFunction->m_lineInfo);
    
    gmFunctionInfo info;
    info.m_id = id;
    info.m_root = false;
    info.m_byteCode = m_currentFunction->m_byteCode.GetData();
    info.m_byteCodeLength = m_currentFunction->m_byteCode.Tell();
    info.m_numParams = numParams;
    info.m_numLocals = m_currentFunction->m_numLocals - numParams;
    info.m_symbols = locals;
    info.m_maxStackSize = m_currentFunction->m_byteCode.GetMaxTos();
    info.m_lineInfoCount = m_currentFunction->m_lineInfo.Count();
    info.m_lineInfo = m_currentFunction->m_lineInfo.GetData();
    info.m_debugName = m_currentFunction->m_debugName;
    m_hooks->AddFunction(info);

    //gmByteCodePrint(stdout, info.m_byteCode, info.m_byteCodeLength);
  }

  PopFunction();
  
  return res;
}
Esempio n. 10
0
bool gmCodeGenPrivate::GenExprCall(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_CALL);

  // mark the stack.
  int stackLevel = a_byteCode->GetTos();

  // if callee is a dot function, push left side of dot as 'this'
  const gmCodeTreeNode * callee = a_node->m_children[0];

  if(callee->m_type == CTNT_EXPRESSION && callee->m_subType == CTNET_OPERATION && callee->m_subTypeType == CTNOT_DOT)
  {
    if(!Generate(callee->m_children[0], a_byteCode)) return false;
    a_byteCode->Emit(BC_DUP);
    a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(callee->m_children[1]->m_data.m_string));
  }
  else
  {
    if(a_node->m_children[2])
    {
      if(!Generate(a_node->m_children[2], a_byteCode)) return false;
    }
    else
    {
#if GM_COMPILE_PASS_THIS_ALWAYS

      a_byteCode->Emit(BC_PUSHTHIS);

#else // !GM_COMPILE_PASS_THIS_ALWAYS

      // if the lvalue is a member, pass 'this', otherwise pass 'null'
      bool pushed = false;
      if(callee->m_type == CTNT_EXPRESSION && callee->m_subType == CTNET_IDENTIFIER)
      {
        gmCodeTreeVariableType vtype;
        int offset = m_currentFunction->GetVariableOffset(callee->m_data.m_string, vtype);
        if(((callee->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0) || (offset == -1 && vtype == CTVT_MEMBER))
        {
          a_byteCode->Emit(BC_PUSHTHIS);
          pushed = true;
        }
      }
      if(!pushed)
      {
        a_byteCode->Emit(BC_PUSHNULL);
      }

#endif // !GM_COMPILE_PASS_THIS_ALWAYS
    }
    if(!Generate(callee, a_byteCode)) return false;
  }

  // push parameters, count the number of parameters
  gmuint32 numParams = 0;

  const gmCodeTreeNode * params = a_node->m_children[1];

  while(params)
  {
    ++numParams;
    if(!Generate(params, a_byteCode, false)) return false;
    params = params->m_sibling;
  }

  // call
  a_byteCode->Emit(BC_CALL, (gmuint32) numParams);

  // restore the stack level.
  a_byteCode->SetTos(stackLevel + 1);

  return true;
}
Esempio n. 11
0
bool gmCodeGenPrivate::GenExprOpAssign(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  // value on left hand side must be an l-value... ie, a dot, array or identifier.
  const gmCodeTreeNode * lValue = a_node->m_children[0];
  int type = 0;

  if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    type = 0;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    if(!Generate(lValue->m_children[1], a_byteCode)) return false;
    type = 1;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER)
  {
    type = 2;
  }
  else
  {
    if(m_log) m_log->LogEntry("error (%d) illegal l-value for '=' operator", a_node->m_lineNumber);
    return false;
  }

  // Generate r-value
  if(!Generate(a_node->m_children[1], a_byteCode)) return false;

  // complete assignment
  if(type == 0)
  {
    a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string));
  }
  else if(type == 1)
  {
    a_byteCode->Emit(BC_SETIND);
  }
  else if(type == 2)
  {
    gmCodeTreeVariableType vtype;
    int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype);

    // if local, set local regardless
    // if member set this
    // if global, set global
    // set and add local

    if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0)
    {
      return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
    }
    if(offset >= 0 && vtype == CTVT_LOCAL)
    {
      return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    }
    else if(offset == -1)
    {
      if(vtype == CTVT_MEMBER)
      {
        return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      else if(vtype == CTVT_GLOBAL)
      {
        return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      if(m_log) m_log->LogEntry("internal error");
      return false;
    }

    offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL);
    return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
  }
  else
  {
    // paranoia
    if(m_log) m_log->LogEntry("internal error");
    return false;
  }

  return true;
}
Esempio n. 12
0
bool gmCodeGenPrivate::GenExprOpPreIncDec(const gmCodeTreeNode * a_node, gmByteCodeGen * a_byteCode)
{
  GM_ASSERT(a_node->m_type == CTNT_EXPRESSION && a_node->m_subType == CTNET_OPERATION);

  // Make sure child 0 is an l-value
  const gmCodeTreeNode * lValue = a_node->m_children[0];
  int type = 0;

  if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_DOT)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    a_byteCode->Emit(BC_DUP);
    a_byteCode->EmitPtr(BC_GETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string));
    type = 0;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_OPERATION && lValue->m_subTypeType == CTNOT_ARRAY_INDEX)
  {
    // Generate half l-value
    if(!Generate(lValue->m_children[0], a_byteCode)) return false;
    if(!Generate(lValue->m_children[1], a_byteCode)) return false;
    a_byteCode->Emit(BC_DUP2);
    a_byteCode->Emit(BC_GETIND);
    type = 1;
  }
  else if(lValue->m_type == CTNT_EXPRESSION && lValue->m_subType == CTNET_IDENTIFIER)
  {
    if(!Generate(lValue, a_byteCode)) return false;
    type = 2;
  }
  else
  {
    if(m_log) m_log->LogEntry("illegal l-value for '++/--' operator, line %d", a_node->m_lineNumber);
    return false;
  }

  // Perform inc/dec
  switch(a_node->m_subTypeType)
  {
    case CTNOT_PRE_INC : a_byteCode->Emit(BC_OP_INC); break;
    case CTNOT_PRE_DEC : a_byteCode->Emit(BC_OP_DEC); break;
    default :
    {
      if(m_log) m_log->LogEntry("unkown operator");
      return false;
    }
  }

  // Write back the value
  if(type == 0)
  {
    int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL);
    a_byteCode->Emit(BC_DUP);
    a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    a_byteCode->EmitPtr(BC_SETDOT, m_hooks->GetSymbolId(lValue->m_children[1]->m_data.m_string));
    a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset);
  }
  else if(type == 1)
  {
    int offset = m_currentFunction->SetVariableType(s_tempVarName0, CTVT_LOCAL);
    a_byteCode->Emit(BC_DUP);
    a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    a_byteCode->Emit(BC_SETIND);
    a_byteCode->Emit(BC_GETLOCAL, (gmuint32) offset);
  }
  else if(type == 2)
  {
    a_byteCode->Emit(BC_DUP);
    gmCodeTreeVariableType vtype;
    int offset = m_currentFunction->GetVariableOffset(lValue->m_data.m_string, vtype);

    // if local, set local regardless
    // if member set this
    // if global, set global
    // set and add local

    if((lValue->m_flags & gmCodeTreeNode::CTN_MEMBER) > 0)
    {
      return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
    }

    if(offset >= 0 && vtype == CTVT_LOCAL)
    {
      return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
    }
    else if(offset == -1)
    {
      if(vtype == CTVT_MEMBER)
      {
        return a_byteCode->EmitPtr(BC_SETTHIS, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      else if(vtype == CTVT_GLOBAL)
      {
        return a_byteCode->EmitPtr(BC_SETGLOBAL, m_hooks->GetSymbolId(lValue->m_data.m_string));
      }
      if(m_log) m_log->LogEntry("internal error");
      return false;
    }

    offset = m_currentFunction->SetVariableType(lValue->m_data.m_string, CTVT_LOCAL);
    return a_byteCode->Emit(BC_SETLOCAL, (gmuint32) offset);
  }
  else
  {
    // paranoia
    if(m_log) m_log->LogEntry("internal error");
    return false;
  }

  return true;
}
Esempio n. 13
0
void printComparable(llvm::raw_ostream &Out, FunctionState const &State)
{
  Out << "  Function [Index=" << State.getIndex() << "]\n";

  Out << "   Allocas:\n";
  for (auto const &Alloca : State.getAllocas()) {
    Out << "    " << Alloca.getInstructionIndex()
        <<  " =[" << Alloca.getElementCount()
        <<    "x" << Alloca.getElementSize()
        <<  "]\n";
  }

  Out << "   Instruction values [Active=";
  if (State.getActiveInstructionIndex().assigned(0))
    Out << State.getActiveInstructionIndex().get<0>();
  else
    Out << "unassigned";
  Out << "]:\n";

  auto const InstructionCount = State.getInstructionCount();
  for (std::size_t i = 0; i < InstructionCount; ++i) {
    auto const Instruction = State.getInstruction(i);
    auto const Type = Instruction->getType();

    if (llvm::isa<llvm::IntegerType>(Type)) {
      auto const UValue = State.getValueUInt64(Instruction);
      if (UValue.assigned<uint64_t>()) {
        auto const SValue = State.getValueInt64(Instruction);
        assert(SValue.assigned<int64_t>());

        Out << "    " << i << " = (int64_t)" << SValue.get< int64_t>()
                           << ", (uint64_t)" << UValue.get<uint64_t>() << "\n";
      }
    }
    else if (Type->isPointerTy()) {
      auto const Value = State.getValuePtr(Instruction);
      if (Value.assigned<stateptr_ty>()) {
        Out << "    " << i << " = \n";
        // TODO: a comparable pointer representation (this requires us to
        //       determine the allocation that a pointer references, and then
        //       display the pointer value relative to that allocation).
      }
    }
    else if (Type->isFloatTy()) {
      auto const Value = State.getValueFloat(Instruction);
      if (Value.assigned<float>()) {
        Out << "    " << i << " = (float)" << Value.get<float>() << "\n";
      }
    }
    else if (Type->isDoubleTy()) {
      auto const Value = State.getValueDouble(Instruction);
      if (Value.assigned<double>()) {
        Out << "    " << i << " = (double)" << Value.get<double>() << "\n";
      }
    }
    else if (Type->isX86_FP80Ty() || Type->isFP128Ty() || Type->isPPC_FP128Ty())
    {
      auto const Value = State.getValueAPFloat(Instruction);
      if (Value.assigned<llvm::APFloat>()) {
        llvm::SmallString<32> Buffer;
        Value.get<llvm::APFloat>().toString(Buffer);
        Out << "    " << i << " = (long double)" << Buffer << "\n";
      }
    }
  }
}