LCOV - code coverage report
Current view: top level - lib/Target/ARM/MCTargetDesc - ARMUnwindOpAsm.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 78 78 100.0 %
Date: 2017-09-14 15:23:50 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file implements the unwind opcode assmebler for ARM exception handling
      11             : // table.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "ARMUnwindOpAsm.h"
      16             : #include "llvm/Support/ARMEHABI.h"
      17             : #include "llvm/Support/LEB128.h"
      18             : #include "llvm/Support/MathExtras.h"
      19             : #include <cassert>
      20             : 
      21             : using namespace llvm;
      22             : 
      23             : namespace {
      24             : 
      25             :   /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes
      26             :   /// with MSB to LSB per uint32_t ordering.  For example, the first byte will
      27             :   /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,
      28             :   /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.
      29             :   class UnwindOpcodeStreamer {
      30             :   private:
      31             :     SmallVectorImpl<uint8_t> &Vec;
      32             :     size_t Pos = 3;
      33             : 
      34             :   public:
      35         509 :     UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V) {}
      36             : 
      37             :     /// Emit the byte in MSB to LSB per uint32_t order.
      38             :     void EmitByte(uint8_t elem) {
      39        5224 :       Vec[Pos] = elem;
      40        2612 :       Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);
      41             :     }
      42             : 
      43             :     /// Emit the size prefix.
      44             :     void EmitSize(size_t Size) {
      45         192 :       size_t SizeInWords = (Size + 3) / 4;
      46             :       assert(SizeInWords <= 0x100u &&
      47             :              "Only 256 additional words are allowed for unwind opcodes");
      48         384 :       EmitByte(static_cast<uint8_t>(SizeInWords - 1));
      49             :     }
      50             : 
      51             :     /// Emit the personality index prefix.
      52             :     void EmitPersonalityIndex(unsigned PI) {
      53             :       assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&
      54             :              "Invalid personality prefix");
      55         884 :       EmitByte(ARM::EHABI::EHT_COMPACT | PI);
      56             :     }
      57             : 
      58             :     /// Fill the rest of bytes with FINISH opcode.
      59             :     void FillFinishOpcode() {
      60        2252 :       while (Pos < Vec.size())
      61             :         EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);
      62             :     }
      63             :   };
      64             : 
      65             : } // end anonymous namespace
      66             : 
      67         387 : void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
      68         387 :   if (RegSave == 0u)
      69             :     return;
      70             : 
      71             :   // One byte opcode to save register r14 and r11-r4
      72         387 :   if (RegSave & (1u << 4)) {
      73             :     // The one byte opcode will always save r4, thus we can't use the one byte
      74             :     // opcode when r4 is not in .save directive.
      75             : 
      76             :     // Compute the consecutive registers from r4 to r11.
      77         280 :     uint32_t Mask = RegSave & 0xff0u;
      78         560 :     uint32_t Range = countTrailingOnes(Mask >> 5); // Exclude r4.
      79             :     // Mask off non-consecutive registers. Keep r4.
      80         280 :     Mask &= ~(0xffffffe0u << Range);
      81             : 
      82             :     // Emit this opcode when the mask covers every registers.
      83         280 :     uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
      84         280 :     if (UnmaskedReg == 0u) {
      85             :       // Pop r[4 : (4 + n)]
      86           6 :       EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
      87           6 :       RegSave &= 0x000fu;
      88         274 :     } else if (UnmaskedReg == (1u << 14)) {
      89             :       // Pop r[14] + r[4 : (4 + n)]
      90         137 :       EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
      91         137 :       RegSave &= 0x000fu;
      92             :     }
      93             :   }
      94             : 
      95             :   // Two bytes opcode to save register r15-r4
      96         387 :   if ((RegSave & 0xfff0u) != 0)
      97         239 :     EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));
      98             : 
      99             :   // Opcode to save register r3-r0
     100         387 :   if ((RegSave & 0x000fu) != 0)
     101           8 :     EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));
     102             : }
     103             : 
     104             : /// Emit unwind opcodes for .vsave directives
     105          11 : void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
     106             :   // We only have 4 bits to save the offset in the opcode so look at the lower
     107             :   // and upper 16 bits separately.
     108          44 :   for (uint32_t Regs : {VFPRegSave & 0xffff0000u, VFPRegSave & 0x0000ffffu}) {
     109          44 :     while (Regs) {
     110             :       // Now look for a run of set bits. Remember the MSB and LSB of the run.
     111          11 :       auto RangeMSB = 32 - countLeadingZeros(Regs);
     112          22 :       auto RangeLen = countLeadingOnes(Regs << (32 - RangeMSB));
     113          11 :       auto RangeLSB = RangeMSB - RangeLen;
     114             : 
     115          11 :       int Opcode = RangeLSB >= 16
     116          11 :                        ? ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16
     117             :                        : ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD;
     118             : 
     119          11 :       EmitInt16(Opcode | ((RangeLSB % 16) << 4) | (RangeLen - 1));
     120             : 
     121             :       // Zero out bits we're done with.
     122          11 :       Regs &= ~(-1u << RangeLSB);
     123             :     }
     124             :   }
     125          11 : }
     126             : 
     127             : /// Emit unwind opcodes to copy address from source register to $sp.
     128          70 : void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {
     129          70 :   EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);
     130          70 : }
     131             : 
     132             : /// Emit unwind opcodes to add $sp with an offset.
     133         388 : void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
     134         388 :   if (Offset > 0x200) {
     135             :     uint8_t Buff[16];
     136         149 :     Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;
     137         298 :     size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);
     138         149 :     EmitBytes(Buff, ULEBSize + 1);
     139         239 :   } else if (Offset > 0) {
     140         176 :     if (Offset > 0x100) {
     141           5 :       EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);
     142           5 :       Offset -= 0x100;
     143             :     }
     144         176 :     EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |
     145         176 :              static_cast<uint8_t>((Offset - 4) >> 2));
     146          63 :   } else if (Offset < 0) {
     147          67 :     while (Offset < -0x100) {
     148           6 :       EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);
     149           6 :       Offset += 0x100;
     150             :     }
     151          55 :     EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |
     152          55 :              static_cast<uint8_t>(((-Offset) - 4) >> 2));
     153             :   }
     154         388 : }
     155             : 
     156         509 : void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,
     157             :                                      SmallVectorImpl<uint8_t> &Result) {
     158         509 :   UnwindOpcodeStreamer OpStreamer(Result);
     159             : 
     160         509 :   if (HasPersonality) {
     161             :     // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]
     162          67 :     PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;
     163         134 :     size_t TotalSize = Ops.size() + 1;
     164          67 :     size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
     165          67 :     Result.resize(RoundUpSize);
     166             :     OpStreamer.EmitSize(RoundUpSize);
     167             :   } else {
     168             :     // If no personalityindex is specified, select ane
     169         442 :     if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)
     170         872 :       PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0
     171             :                                            : ARM::EHABI::AEABI_UNWIND_CPP_PR1;
     172         442 :     if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {
     173             :       // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
     174             :       assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");
     175         317 :       Result.resize(4);
     176         317 :       OpStreamer.EmitPersonalityIndex(PersonalityIndex);
     177             :     } else {
     178             :       // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]
     179         250 :       size_t TotalSize = Ops.size() + 2;
     180         125 :       size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
     181         125 :       Result.resize(RoundUpSize);
     182         250 :       OpStreamer.EmitPersonalityIndex(PersonalityIndex);
     183             :       OpStreamer.EmitSize(RoundUpSize);
     184             :     }
     185             :   }
     186             : 
     187             :   // Copy the unwind opcodes
     188        1018 :   for (size_t i = OpBegins.size() - 1; i > 0; --i)
     189        4091 :     for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)
     190        4083 :       OpStreamer.EmitByte(Ops[j]);
     191             : 
     192             :   // Emit the padding finish opcodes if the size is not multiple of 4.
     193         509 :   OpStreamer.FillFinishOpcode();
     194             : 
     195             :   // Reset the assembler state
     196         509 :   Reset();
     197         509 : }

Generated by: LCOV version 1.13