[MIPS] Avoid breakpoint in delay slot
    
    SUMMARY:
    This patch implements Target::GetBreakableLoadAddress() method that takes an address
    and checks for any reason there is a better address than this to put a breakpoint on.
    If there is then return that address.
    MIPS uses this method to avoid breakpoint in delay slot.
    
    Reviewers: clayborg, jingham
    Subscribers: jingham, mohit.bhakkad, sagar, jaydeep, nitesh.jain, lldb-commits
    Differential Revision: http://http://reviews.llvm.org/D12184

llvm-svn: 246015
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
index 02e39d3..19e2dbd 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -52,6 +52,7 @@
         Instruction (address, addr_class),
         m_disasm_sp (disasm.shared_from_this()),
         m_does_branch (eLazyBoolCalculate),
+        m_has_delay_slot (eLazyBoolCalculate),
         m_is_valid (false),
         m_using_file_addr (false)
     {
@@ -99,6 +100,43 @@
         return m_does_branch == eLazyBoolYes;
     }
 
+    virtual bool
+    HasDelaySlot ()
+    {
+        if (m_has_delay_slot == eLazyBoolCalculate)
+        {
+            GetDisassemblerLLVMC().Lock(this, NULL);
+            DataExtractor data;
+            if (m_opcode.GetData(data))
+            {
+                bool is_alternate_isa;
+                lldb::addr_t pc = m_address.GetFileAddress();
+
+                DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
+                const uint8_t *opcode_data = data.GetDataStart();
+                const size_t opcode_data_len = data.GetByteSize();
+                llvm::MCInst inst;
+                const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
+                                                                   opcode_data_len,
+                                                                   pc,
+                                                                   inst);
+                // if we didn't understand the instruction, say it doesn't have a delay slot...
+                if (inst_size == 0)
+                    m_has_delay_slot = eLazyBoolNo;
+                else
+                {
+                    const bool has_delay_slot = mc_disasm_ptr->HasDelaySlot(inst);
+                    if (has_delay_slot)
+                        m_has_delay_slot = eLazyBoolYes;
+                    else
+                        m_has_delay_slot = eLazyBoolNo;
+                }
+            }
+            GetDisassemblerLLVMC().Unlock();
+        }
+        return m_has_delay_slot == eLazyBoolYes;
+    }
+
     DisassemblerLLVMC::LLVMCDisassembler *
     GetDisasmToUse (bool &is_alternate_isa)
     {
@@ -409,6 +447,7 @@
 
     DisassemblerSP          m_disasm_sp; // for ownership
     LazyBool                m_does_branch;
+    LazyBool                m_has_delay_slot;
     bool                    m_is_valid;
     bool                    m_using_file_addr;
 };
@@ -543,6 +582,12 @@
 }
 
 bool
+DisassemblerLLVMC::LLVMCDisassembler::HasDelaySlot (llvm::MCInst &mc_inst)
+{
+    return m_instr_info_ap->get(mc_inst.getOpcode()).hasDelaySlot();
+}
+
+bool
 DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor)
 {
     llvm::Triple triple = arch.GetTriple();
diff --git a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
index 56cec03..4e32951 100644
--- a/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
+++ b/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -49,6 +49,7 @@
         uint64_t PrintMCInst (llvm::MCInst &mc_inst, char *output_buffer, size_t out_buffer_len);
         void     SetStyle (bool use_hex_immed, HexImmediateStyle hex_style);
         bool     CanBranch (llvm::MCInst &mc_inst);
+        bool     HasDelaySlot (llvm::MCInst &mc_inst);
         bool     IsValid()
         {
             return m_is_valid;