Implemented a feature where the expression parser
can avoid running the code in the target if the
expression's result is known and the expression
has no side effects.

Right now this feature is quite conservative in
its guess about side effects, and it only computes
integer results, but the machinery to make it more
sophisticated is there.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@121952 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index be6d709..302ebf8 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -20,6 +20,7 @@
 #include "lldb/Core/Error.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectConstResult.h"
 #include "lldb/Expression/ClangASTSource.h"
 #include "lldb/Expression/ClangPersistentVariables.h"
 #include "lldb/Symbol/ClangASTContext.h"
@@ -121,6 +122,78 @@
     return m_struct_vars->m_result_name;
 }
 
+lldb::ClangExpressionVariableSP
+ClangExpressionDeclMap::BuildIntegerVariable (const ConstString &name,
+                                              lldb_private::TypeFromParser type,
+                                              const llvm::APInt& value)
+{
+    assert (m_parser_vars.get());
+
+    
+    clang::ASTContext *context(m_parser_vars->m_exe_ctx->target->GetScratchClangASTContext()->getASTContext());
+    
+    TypeFromUser user_type(ClangASTContext::CopyType(context, 
+                                                     type.GetASTContext(),
+                                                     type.GetOpaqueQualType()),
+                           context);
+    
+    DataBufferHeap *heap_data_buf = new DataBufferHeap(ClangASTType::GetClangTypeBitWidth(user_type.GetASTContext(),
+                                                                                          user_type.GetOpaqueQualType()) / 8,
+                                                       '\0');
+    
+    DataBufferSP data_sp(heap_data_buf);
+    
+    uint64_t value64 = value.getLimitedValue();
+    
+    ByteOrder byte_order = m_parser_vars->m_exe_ctx->process->GetByteOrder();
+    
+    size_t num_val_bytes = sizeof(value64);
+    size_t num_data_bytes = heap_data_buf->GetByteSize();
+    
+    size_t num_bytes = num_val_bytes;
+    if (num_bytes > num_data_bytes)
+        num_bytes = num_data_bytes;
+    
+    uint8_t *data_bytes = heap_data_buf->GetBytes();
+    
+    for (off_t byte_idx = 0;
+         byte_idx < num_bytes;
+         ++byte_idx)
+    {
+        uint64_t shift = byte_idx * 8;
+        uint64_t mask = 0xffll << shift;
+        uint8_t cur_byte = (uint8_t)((value64 & mask) >> shift);
+        
+        switch (byte_order)
+        {
+        case eByteOrderBig:
+            //                    High         Low
+            // Original:         |AABBCCDDEEFFGGHH|
+            // Target:                   |EEFFGGHH|
+            
+            data_bytes[num_data_bytes - (1 + byte_idx)] = cur_byte;
+            break;
+        case eByteOrderLittle:
+            // Target:                   |HHGGFFEE|
+            data_bytes[byte_idx] = cur_byte;
+            break;
+        default:
+            return lldb::ClangExpressionVariableSP();    
+        }
+    }
+    
+    ValueObjectSP valobj_sp(new ValueObjectConstResult(user_type.GetASTContext(),
+                                                       user_type.GetOpaqueQualType(),
+                                                       name,
+                                                       data_sp,
+                                                       m_parser_vars->m_exe_ctx->process->GetByteOrder(), 
+                                                       m_parser_vars->m_exe_ctx->process->GetAddressByteSize()));
+    
+    ClangExpressionVariableSP var_sp(new ClangExpressionVariable(valobj_sp));
+    
+    return var_sp;
+}
+
 bool 
 ClangExpressionDeclMap::AddPersistentVariable 
 (
diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp
index 80ce515..9fff48d 100644
--- a/source/Expression/ClangExpressionParser.cpp
+++ b/source/Expression/ClangExpressionParser.cpp
@@ -409,7 +409,8 @@
 Error
 ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, 
                                 lldb::addr_t &func_end, 
-                                ExecutionContext &exe_ctx)
+                                ExecutionContext &exe_ctx,
+                                lldb::ClangExpressionVariableSP *const_result)
 {
     lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
 
@@ -446,6 +447,7 @@
     {
         IRForTarget ir_for_target(decl_map, 
                                   m_expr.NeedsVariableResolution(),
+                                  const_result,
                                   function_name.c_str());
         
         if (!ir_for_target.runOnModule(*module))
diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
index 278cee7..0085c8a 100644
--- a/source/Expression/ClangUserExpression.cpp
+++ b/source/Expression/ClangUserExpression.cpp
@@ -22,10 +22,11 @@
 #include "lldb/Core/Log.h"
 #include "lldb/Core/StreamString.h"
 #include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Expression/ASTSplitConsumer.h"
+#include "lldb/Expression/ASTResultSynthesizer.h"
 #include "lldb/Expression/ClangExpressionDeclMap.h"
 #include "lldb/Expression/ClangExpressionParser.h"
 #include "lldb/Expression/ClangFunction.h"
-#include "lldb/Expression/ASTResultSynthesizer.h"
 #include "lldb/Expression/ClangUserExpression.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Symbol/VariableList.h"
@@ -143,7 +144,8 @@
 bool
 ClangUserExpression::Parse (Stream &error_stream, 
                             ExecutionContext &exe_ctx,
-                            TypeFromUser desired_type)
+                            TypeFromUser desired_type,
+                            lldb::ClangExpressionVariableSP *const_result)
 {
     lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
     
@@ -292,8 +294,8 @@
     m_dwarf_opcodes.reset();
     
     lldb::addr_t jit_end;
-    
-    Error jit_error = parser.MakeJIT (m_jit_addr, jit_end, exe_ctx);
+        
+    Error jit_error = parser.MakeJIT (m_jit_addr, jit_end, exe_ctx, const_result);
     
     m_expr_decl_map->DidParse();
     
@@ -601,10 +603,12 @@
 
     StreamString error_stream;
     
+    lldb::ClangExpressionVariableSP const_result;
+    
     if (log)
         log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr);
     
-    if (!user_expression_sp->Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL)))
+    if (!user_expression_sp->Parse (error_stream, exe_ctx, TypeFromUser(NULL, NULL), &const_result))
     {
         if (error_stream.GetString().empty())
             error.SetErrorString ("expression failed to parse, unknown error");
@@ -615,41 +619,52 @@
     {
         lldb::ClangExpressionVariableSP expr_result;
 
-        error_stream.GetString().clear();
-        
-        if (log)
-            log->Printf("== [ClangUserExpression::Evaluate] Executing expression ==");
-
-        execution_results = user_expression_sp->Execute (error_stream, 
-                                                         exe_ctx, 
-                                                         discard_on_error, 
-                                                         user_expression_sp, 
-                                                         expr_result);
-        if (execution_results != lldb::eExecutionCompleted)
+        if (const_result.get())
         {
             if (log)
-                log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally ==");
+                log->Printf("== [ClangUserExpression::Evaluate] Expression evaluated as a constant ==");
             
-            if (error_stream.GetString().empty())
-                error.SetErrorString ("expression failed to execute, unknown error");
-            else
-                error.SetErrorString (error_stream.GetString().c_str());
+            result_valobj_sp = const_result->GetValueObject();
         }
-        else 
-        {
-            if (expr_result)
+        else
+        {    
+            error_stream.GetString().clear();
+            
+            if (log)
+                log->Printf("== [ClangUserExpression::Evaluate] Executing expression ==");
+
+            execution_results = user_expression_sp->Execute (error_stream, 
+                                                             exe_ctx, 
+                                                             discard_on_error, 
+                                                             user_expression_sp, 
+                                                             expr_result);
+            
+            if (execution_results != lldb::eExecutionCompleted)
             {
-                result_valobj_sp = expr_result->GetValueObject();
-                
                 if (log)
-                    log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString(exe_ctx.GetBestExecutionContextScope()));
+                    log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally ==");
+                
+                if (error_stream.GetString().empty())
+                    error.SetErrorString ("expression failed to execute, unknown error");
+                else
+                    error.SetErrorString (error_stream.GetString().c_str());
             }
-            else
+            else 
             {
-                if (log)
-                    log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result ==");
-                
-                error.SetErrorString ("Expression did not return a result");
+                if (expr_result)
+                {
+                    result_valobj_sp = expr_result->GetValueObject();
+                    
+                    if (log)
+                        log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString(exe_ctx.GetBestExecutionContextScope()));
+                }
+                else
+                {
+                    if (log)
+                        log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result ==");
+                    
+                    error.SetErrorString ("Expression did not return a result");
+                }
             }
         }
     }
diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp
index 34f146f..ab3afeb 100644
--- a/source/Expression/IRForTarget.cpp
+++ b/source/Expression/IRForTarget.cpp
@@ -34,13 +34,16 @@
 
 IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
                           bool resolve_vars,
+                          lldb::ClangExpressionVariableSP *const_result,
                           const char *func_name) :
     ModulePass(ID),
     m_decl_map(decl_map),
     m_CFStringCreateWithBytes(NULL),
     m_sel_registerName(NULL),
     m_func_name(func_name),
-    m_resolve_vars(resolve_vars)
+    m_resolve_vars(resolve_vars),
+    m_const_result(const_result),
+    m_has_side_effects(NULL)
 {
 }
 
@@ -75,6 +78,64 @@
 }
 
 bool 
+IRForTarget::HasSideEffects (llvm::Module &llvm_module,
+                             llvm::Function &llvm_function)
+{
+    llvm::Function::iterator bbi;
+    BasicBlock::iterator ii;
+    
+    for (bbi = llvm_function.begin();
+         bbi != llvm_function.end();
+         ++bbi)
+    {
+        BasicBlock &basic_block = *bbi;
+        
+        for (ii = basic_block.begin();
+             ii != basic_block.end();
+             ++ii)
+        {      
+            switch (ii->getOpcode())
+            {
+            default:
+                return true;
+            case Instruction::Store:
+                {
+                    StoreInst *store_inst = dyn_cast<StoreInst>(ii);
+                    
+                    Value *store_ptr = store_inst->getPointerOperand();
+                    
+                    if (!isa <AllocaInst> (store_ptr))
+                        return true;
+                    else
+                        break;
+                }
+            case Instruction::Load:
+            case Instruction::Alloca:
+            case Instruction::GetElementPtr:
+            case Instruction::Ret:
+                break;
+            }
+        }
+    }
+    
+    return false;
+}
+
+void 
+IRForTarget::MaybeSetConstantResult (llvm::Constant *initializer,
+                                     const lldb_private::ConstString &name,
+                                     lldb_private::TypeFromParser type)
+{
+    if (!m_const_result)
+        return;
+    
+    if (llvm::ConstantInt *init_int = dyn_cast<llvm::ConstantInt>(initializer))
+    {
+        *m_const_result = m_decl_map->BuildIntegerVariable(name, type, init_int->getValue());
+    }
+}
+
+bool 
 IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &llvm_function)
 {
     lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@@ -239,6 +300,16 @@
         }
         
         Constant *initializer = result_global->getInitializer();
+        
+        // Here we write the initializer into a result variable assuming it
+        // can be computed statically.
+        
+        if (!m_has_side_effects)
+        {
+            MaybeSetConstantResult (initializer, 
+                                    new_result_name, 
+                                    result_decl_type);
+        }
                 
         StoreInst *synthesized_store = new StoreInst::StoreInst(initializer,
                                                                 new_result_global,
@@ -1442,6 +1513,8 @@
         
     Function::iterator bbi;
     
+    m_has_side_effects = HasSideEffects(llvm_module, *function);
+    
     ////////////////////////////////////////////////////////////
     // Replace $__lldb_expr_result with a persistent variable
     //
@@ -1456,19 +1529,7 @@
     ///////////////////////////////////////////////////////////////////////////////
     // Fix all Objective-C constant strings to use NSStringWithCString:encoding:
     //
-    
-    if (log)
-    {
-        std::string s;
-        raw_string_ostream oss(s);
         
-        llvm_module.print(oss, NULL);
-        
-        oss.flush();
-        
-        log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str());
-    }
-    
     if (!RewriteObjCConstStrings(llvm_module, *function))
     {
         if (log)
@@ -1476,18 +1537,6 @@
         return false;
     }
     
-    if (log)
-    {
-        std::string s;
-        raw_string_ostream oss(s);
-        
-        llvm_module.print(oss, NULL);
-        
-        oss.flush();
-        
-        log->Printf("Module after rewriting Objective-C const strings: \n\"%s\"", s.c_str());
-    }
-    
     //////////////////////////////////
     // Run basic-block level passes
     //