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