xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg //===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
9*82d56013Sjoerg // This file implements the unwind opcode assembler for ARM exception handling
107330f729Sjoerg // table.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg 
147330f729Sjoerg #include "ARMUnwindOpAsm.h"
157330f729Sjoerg #include "llvm/Support/ARMEHABI.h"
167330f729Sjoerg #include "llvm/Support/LEB128.h"
177330f729Sjoerg #include "llvm/Support/MathExtras.h"
187330f729Sjoerg #include <cassert>
197330f729Sjoerg 
207330f729Sjoerg using namespace llvm;
217330f729Sjoerg 
227330f729Sjoerg namespace {
237330f729Sjoerg 
247330f729Sjoerg   /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes
257330f729Sjoerg   /// with MSB to LSB per uint32_t ordering.  For example, the first byte will
267330f729Sjoerg   /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,
277330f729Sjoerg   /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.
287330f729Sjoerg   class UnwindOpcodeStreamer {
297330f729Sjoerg   private:
307330f729Sjoerg     SmallVectorImpl<uint8_t> &Vec;
317330f729Sjoerg     size_t Pos = 3;
327330f729Sjoerg 
337330f729Sjoerg   public:
UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> & V)347330f729Sjoerg     UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V) {}
357330f729Sjoerg 
367330f729Sjoerg     /// Emit the byte in MSB to LSB per uint32_t order.
EmitByte(uint8_t elem)377330f729Sjoerg     void EmitByte(uint8_t elem) {
387330f729Sjoerg       Vec[Pos] = elem;
397330f729Sjoerg       Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);
407330f729Sjoerg     }
417330f729Sjoerg 
427330f729Sjoerg     /// Emit the size prefix.
EmitSize(size_t Size)437330f729Sjoerg     void EmitSize(size_t Size) {
447330f729Sjoerg       size_t SizeInWords = (Size + 3) / 4;
457330f729Sjoerg       assert(SizeInWords <= 0x100u &&
467330f729Sjoerg              "Only 256 additional words are allowed for unwind opcodes");
477330f729Sjoerg       EmitByte(static_cast<uint8_t>(SizeInWords - 1));
487330f729Sjoerg     }
497330f729Sjoerg 
507330f729Sjoerg     /// Emit the personality index prefix.
EmitPersonalityIndex(unsigned PI)517330f729Sjoerg     void EmitPersonalityIndex(unsigned PI) {
527330f729Sjoerg       assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&
537330f729Sjoerg              "Invalid personality prefix");
547330f729Sjoerg       EmitByte(ARM::EHABI::EHT_COMPACT | PI);
557330f729Sjoerg     }
567330f729Sjoerg 
577330f729Sjoerg     /// Fill the rest of bytes with FINISH opcode.
FillFinishOpcode()587330f729Sjoerg     void FillFinishOpcode() {
597330f729Sjoerg       while (Pos < Vec.size())
607330f729Sjoerg         EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);
617330f729Sjoerg     }
627330f729Sjoerg   };
637330f729Sjoerg 
647330f729Sjoerg } // end anonymous namespace
657330f729Sjoerg 
EmitRegSave(uint32_t RegSave)667330f729Sjoerg void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
677330f729Sjoerg   if (RegSave == 0u)
687330f729Sjoerg     return;
697330f729Sjoerg 
707330f729Sjoerg   // One byte opcode to save register r14 and r11-r4
717330f729Sjoerg   if (RegSave & (1u << 4)) {
727330f729Sjoerg     // The one byte opcode will always save r4, thus we can't use the one byte
737330f729Sjoerg     // opcode when r4 is not in .save directive.
747330f729Sjoerg 
757330f729Sjoerg     // Compute the consecutive registers from r4 to r11.
767330f729Sjoerg     uint32_t Mask = RegSave & 0xff0u;
777330f729Sjoerg     uint32_t Range = countTrailingOnes(Mask >> 5); // Exclude r4.
787330f729Sjoerg     // Mask off non-consecutive registers. Keep r4.
797330f729Sjoerg     Mask &= ~(0xffffffe0u << Range);
807330f729Sjoerg 
817330f729Sjoerg     // Emit this opcode when the mask covers every registers.
827330f729Sjoerg     uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
837330f729Sjoerg     if (UnmaskedReg == 0u) {
847330f729Sjoerg       // Pop r[4 : (4 + n)]
857330f729Sjoerg       EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
867330f729Sjoerg       RegSave &= 0x000fu;
877330f729Sjoerg     } else if (UnmaskedReg == (1u << 14)) {
887330f729Sjoerg       // Pop r[14] + r[4 : (4 + n)]
897330f729Sjoerg       EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
907330f729Sjoerg       RegSave &= 0x000fu;
917330f729Sjoerg     }
927330f729Sjoerg   }
937330f729Sjoerg 
947330f729Sjoerg   // Two bytes opcode to save register r15-r4
957330f729Sjoerg   if ((RegSave & 0xfff0u) != 0)
967330f729Sjoerg     EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));
977330f729Sjoerg 
987330f729Sjoerg   // Opcode to save register r3-r0
997330f729Sjoerg   if ((RegSave & 0x000fu) != 0)
1007330f729Sjoerg     EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));
1017330f729Sjoerg }
1027330f729Sjoerg 
1037330f729Sjoerg /// Emit unwind opcodes for .vsave directives
EmitVFPRegSave(uint32_t VFPRegSave)1047330f729Sjoerg void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
1057330f729Sjoerg   // We only have 4 bits to save the offset in the opcode so look at the lower
1067330f729Sjoerg   // and upper 16 bits separately.
1077330f729Sjoerg   for (uint32_t Regs : {VFPRegSave & 0xffff0000u, VFPRegSave & 0x0000ffffu}) {
1087330f729Sjoerg     while (Regs) {
1097330f729Sjoerg       // Now look for a run of set bits. Remember the MSB and LSB of the run.
1107330f729Sjoerg       auto RangeMSB = 32 - countLeadingZeros(Regs);
1117330f729Sjoerg       auto RangeLen = countLeadingOnes(Regs << (32 - RangeMSB));
1127330f729Sjoerg       auto RangeLSB = RangeMSB - RangeLen;
1137330f729Sjoerg 
1147330f729Sjoerg       int Opcode = RangeLSB >= 16
1157330f729Sjoerg                        ? ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16
1167330f729Sjoerg                        : ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD;
1177330f729Sjoerg 
1187330f729Sjoerg       EmitInt16(Opcode | ((RangeLSB % 16) << 4) | (RangeLen - 1));
1197330f729Sjoerg 
1207330f729Sjoerg       // Zero out bits we're done with.
1217330f729Sjoerg       Regs &= ~(-1u << RangeLSB);
1227330f729Sjoerg     }
1237330f729Sjoerg   }
1247330f729Sjoerg }
1257330f729Sjoerg 
1267330f729Sjoerg /// Emit unwind opcodes to copy address from source register to $sp.
EmitSetSP(uint16_t Reg)1277330f729Sjoerg void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {
1287330f729Sjoerg   EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);
1297330f729Sjoerg }
1307330f729Sjoerg 
1317330f729Sjoerg /// Emit unwind opcodes to add $sp with an offset.
EmitSPOffset(int64_t Offset)1327330f729Sjoerg void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
1337330f729Sjoerg   if (Offset > 0x200) {
1347330f729Sjoerg     uint8_t Buff[16];
1357330f729Sjoerg     Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;
1367330f729Sjoerg     size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);
137*82d56013Sjoerg     emitBytes(Buff, ULEBSize + 1);
1387330f729Sjoerg   } else if (Offset > 0) {
1397330f729Sjoerg     if (Offset > 0x100) {
1407330f729Sjoerg       EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);
1417330f729Sjoerg       Offset -= 0x100;
1427330f729Sjoerg     }
1437330f729Sjoerg     EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |
1447330f729Sjoerg              static_cast<uint8_t>((Offset - 4) >> 2));
1457330f729Sjoerg   } else if (Offset < 0) {
1467330f729Sjoerg     while (Offset < -0x100) {
1477330f729Sjoerg       EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);
1487330f729Sjoerg       Offset += 0x100;
1497330f729Sjoerg     }
1507330f729Sjoerg     EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |
1517330f729Sjoerg              static_cast<uint8_t>(((-Offset) - 4) >> 2));
1527330f729Sjoerg   }
1537330f729Sjoerg }
1547330f729Sjoerg 
Finalize(unsigned & PersonalityIndex,SmallVectorImpl<uint8_t> & Result)1557330f729Sjoerg void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,
1567330f729Sjoerg                                      SmallVectorImpl<uint8_t> &Result) {
1577330f729Sjoerg   UnwindOpcodeStreamer OpStreamer(Result);
1587330f729Sjoerg 
1597330f729Sjoerg   if (HasPersonality) {
1607330f729Sjoerg     // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]
1617330f729Sjoerg     PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;
1627330f729Sjoerg     size_t TotalSize = Ops.size() + 1;
1637330f729Sjoerg     size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
1647330f729Sjoerg     Result.resize(RoundUpSize);
1657330f729Sjoerg     OpStreamer.EmitSize(RoundUpSize);
1667330f729Sjoerg   } else {
1677330f729Sjoerg     // If no personalityindex is specified, select ane
1687330f729Sjoerg     if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)
1697330f729Sjoerg       PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0
1707330f729Sjoerg                                            : ARM::EHABI::AEABI_UNWIND_CPP_PR1;
1717330f729Sjoerg     if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {
1727330f729Sjoerg       // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
1737330f729Sjoerg       assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");
1747330f729Sjoerg       Result.resize(4);
1757330f729Sjoerg       OpStreamer.EmitPersonalityIndex(PersonalityIndex);
1767330f729Sjoerg     } else {
1777330f729Sjoerg       // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]
1787330f729Sjoerg       size_t TotalSize = Ops.size() + 2;
1797330f729Sjoerg       size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
1807330f729Sjoerg       Result.resize(RoundUpSize);
1817330f729Sjoerg       OpStreamer.EmitPersonalityIndex(PersonalityIndex);
1827330f729Sjoerg       OpStreamer.EmitSize(RoundUpSize);
1837330f729Sjoerg     }
1847330f729Sjoerg   }
1857330f729Sjoerg 
1867330f729Sjoerg   // Copy the unwind opcodes
1877330f729Sjoerg   for (size_t i = OpBegins.size() - 1; i > 0; --i)
1887330f729Sjoerg     for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)
1897330f729Sjoerg       OpStreamer.EmitByte(Ops[j]);
1907330f729Sjoerg 
1917330f729Sjoerg   // Emit the padding finish opcodes if the size is not multiple of 4.
1927330f729Sjoerg   OpStreamer.FillFinishOpcode();
1937330f729Sjoerg 
1947330f729Sjoerg   // Reset the assembler state
1957330f729Sjoerg   Reset();
1967330f729Sjoerg }
197