]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / lib / Target / ARM / MCTargetDesc / ARMUnwindOpAsm.cpp
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
17 #include "ARMUnwindOp.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/LEB128.h"
20
21 using namespace llvm;
22
23 void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
24   if (RegSave == 0u)
25     return;
26
27   // One byte opcode to save register r14 and r11-r4
28   if (RegSave & (1u << 4)) {
29     // The one byte opcode will always save r4, thus we can't use the one byte
30     // opcode when r4 is not in .save directive.
31
32     // Compute the consecutive registers from r4 to r11.
33     uint32_t Range = 0;
34     uint32_t Mask = (1u << 4);
35     for (uint32_t Bit = (1u << 5); Bit < (1u << 12); Bit <<= 1) {
36       if ((RegSave & Bit) == 0u)
37         break;
38       ++Range;
39       Mask |= Bit;
40     }
41
42     // Emit this opcode when the mask covers every registers.
43     uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
44     if (UnmaskedReg == 0u) {
45       // Pop r[4 : (4 + n)]
46       Ops.push_back(UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
47       RegSave &= 0x000fu;
48     } else if (UnmaskedReg == (1u << 14)) {
49       // Pop r[14] + r[4 : (4 + n)]
50       Ops.push_back(UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
51       RegSave &= 0x000fu;
52     }
53   }
54
55   // Two bytes opcode to save register r15-r4
56   if ((RegSave & 0xfff0u) != 0) {
57     uint32_t Op = UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4);
58     Ops.push_back(static_cast<uint8_t>(Op >> 8));
59     Ops.push_back(static_cast<uint8_t>(Op & 0xff));
60   }
61
62   // Opcode to save register r3-r0
63   if ((RegSave & 0x000fu) != 0) {
64     uint32_t Op = UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu);
65     Ops.push_back(static_cast<uint8_t>(Op >> 8));
66     Ops.push_back(static_cast<uint8_t>(Op & 0xff));
67   }
68 }
69
70 /// Emit unwind opcodes for .vsave directives
71 void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
72   size_t i = 32;
73
74   while (i > 16) {
75     uint32_t Bit = 1u << (i - 1);
76     if ((VFPRegSave & Bit) == 0u) {
77       --i;
78       continue;
79     }
80
81     uint32_t Range = 0;
82
83     --i;
84     Bit >>= 1;
85
86     while (i > 16 && (VFPRegSave & Bit)) {
87       --i;
88       ++Range;
89       Bit >>= 1;
90     }
91
92     uint32_t Op =
93         UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16 | ((i - 16) << 4) | Range;
94     Ops.push_back(static_cast<uint8_t>(Op >> 8));
95     Ops.push_back(static_cast<uint8_t>(Op & 0xff));
96   }
97
98   while (i > 0) {
99     uint32_t Bit = 1u << (i - 1);
100     if ((VFPRegSave & Bit) == 0u) {
101       --i;
102       continue;
103     }
104
105     uint32_t Range = 0;
106
107     --i;
108     Bit >>= 1;
109
110     while (i > 0 && (VFPRegSave & Bit)) {
111       --i;
112       ++Range;
113       Bit >>= 1;
114     }
115
116     uint32_t Op = UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD | (i << 4) | Range;
117     Ops.push_back(static_cast<uint8_t>(Op >> 8));
118     Ops.push_back(static_cast<uint8_t>(Op & 0xff));
119   }
120 }
121
122 /// Emit unwind opcodes for .setfp directives
123 void UnwindOpcodeAssembler::EmitSetFP(uint16_t FPReg) {
124   Ops.push_back(UNWIND_OPCODE_SET_VSP | FPReg);
125 }
126
127 /// Emit unwind opcodes to update stack pointer
128 void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
129   if (Offset > 0x200) {
130     uint8_t Buff[10];
131     size_t Size = encodeULEB128((Offset - 0x204) >> 2, Buff);
132     Ops.push_back(UNWIND_OPCODE_INC_VSP_ULEB128);
133     Ops.append(Buff, Buff + Size);
134   } else if (Offset > 0) {
135     if (Offset > 0x100) {
136       Ops.push_back(UNWIND_OPCODE_INC_VSP | 0x3fu);
137       Offset -= 0x100;
138     }
139     Ops.push_back(UNWIND_OPCODE_INC_VSP |
140                   static_cast<uint8_t>((Offset - 4) >> 2));
141   } else if (Offset < 0) {
142     while (Offset < -0x100) {
143       Ops.push_back(UNWIND_OPCODE_DEC_VSP | 0x3fu);
144       Offset += 0x100;
145     }
146     Ops.push_back(UNWIND_OPCODE_DEC_VSP |
147                   static_cast<uint8_t>(((-Offset) - 4) >> 2));
148   }
149 }
150
151 void UnwindOpcodeAssembler::AddOpcodeSizePrefix(size_t Pos) {
152   size_t SizeInWords = (size() + 3) / 4;
153   assert(SizeInWords <= 0x100u &&
154          "Only 256 additional words are allowed for unwind opcodes");
155   Ops[Pos] = static_cast<uint8_t>(SizeInWords - 1);
156 }
157
158 void UnwindOpcodeAssembler::AddPersonalityIndexPrefix(size_t Pos, unsigned PI) {
159   assert(PI < NUM_PERSONALITY_INDEX && "Invalid personality prefix");
160   Ops[Pos] = EHT_COMPACT | PI;
161 }
162
163 void UnwindOpcodeAssembler::EmitFinishOpcodes() {
164   for (size_t i = (0x4u - (size() & 0x3u)) & 0x3u; i > 0; --i)
165     Ops.push_back(UNWIND_OPCODE_FINISH);
166 }
167
168 void UnwindOpcodeAssembler::Finalize() {
169   if (HasPersonality) {
170     // Personality specified by .personality directive
171     Offset = 1;
172     AddOpcodeSizePrefix(1);
173   } else {
174     if (getOpcodeSize() <= 3) {
175       // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
176       Offset = 1;
177       PersonalityIndex = AEABI_UNWIND_CPP_PR0;
178       AddPersonalityIndexPrefix(Offset, PersonalityIndex);
179     } else {
180       // __aeabi_unwind_cpp_pr1: [ 0x81 , SIZE , OP1 , OP2 , ... ]
181       Offset = 0;
182       PersonalityIndex = AEABI_UNWIND_CPP_PR1;
183       AddPersonalityIndexPrefix(Offset, PersonalityIndex);
184       AddOpcodeSizePrefix(1);
185     }
186   }
187
188   // Emit the padding finish opcodes if the size() is not multiple of 4.
189   EmitFinishOpcodes();
190
191   // Swap the byte order
192   uint8_t *Ptr = Ops.begin() + Offset;
193   assert(size() % 4 == 0 && "Final unwind opcodes should align to 4");
194   for (size_t i = 0, n = size(); i < n; i += 4) {
195     std::swap(Ptr[i], Ptr[i + 3]);
196     std::swap(Ptr[i + 1], Ptr[i + 2]);
197   }
198 }