Add missing break statements. Align UNWIND_INFO and RUNTIME_FUNCTION structs
[oota-llvm.git] / lib / MC / MCWin64EH.cpp
1 //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
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 #include "llvm/MC/MCWin64EH.h"
11 #include "llvm/MC/MCStreamer.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCExpr.h"
14 #include "llvm/Target/TargetAsmInfo.h"
15
16 namespace llvm {
17
18 // NOTE: All relocations generated here are 4-byte image-relative.
19
20 static uint8_t CountOfUnwindCodes(std::vector<MCWin64EHInstruction> &instArray){
21   uint8_t count = 0;
22   for (std::vector<MCWin64EHInstruction>::const_iterator I = instArray.begin(),
23        E = instArray.end(); I != E; ++I) {
24     switch (I->getOperation()) {
25     case Win64EH::UOP_PushNonVol:
26     case Win64EH::UOP_AllocSmall:
27     case Win64EH::UOP_SetFPReg:
28     case Win64EH::UOP_PushMachFrame:
29       count += 1;
30       break;
31     case Win64EH::UOP_SaveNonVol:
32     case Win64EH::UOP_SaveXMM128:
33       count += 2;
34       break;
35     case Win64EH::UOP_SaveNonVolBig:
36     case Win64EH::UOP_SaveXMM128Big:
37       count += 3;
38       break;
39     case Win64EH::UOP_AllocLarge:
40       if (I->getSize() > 512*1024-8)
41         count += 3;
42       else
43         count += 2;
44       break;
45     }
46   }
47   return count;
48 }
49
50 static void EmitUnwindCode(MCStreamer &streamer, MCWin64EHInstruction &inst) {
51   uint8_t b1, b2;
52   uint16_t w;
53   b2 = (inst.getOperation() & 0x0F) << 4;
54   switch (inst.getOperation()) {
55   case Win64EH::UOP_PushNonVol:
56     streamer.EmitIntValue(0, 1);
57     b2 |= inst.getRegister() & 0x0F;
58     streamer.EmitIntValue(b2, 1);
59     break;
60   case Win64EH::UOP_AllocLarge:
61     streamer.EmitIntValue(0, 1);
62     if (inst.getSize() > 512*1024-8) {
63       b2 |= 1;
64       streamer.EmitIntValue(b2, 1);
65       w = inst.getSize() & 0xFFF8;
66       streamer.EmitIntValue(w, 2);
67       w = inst.getSize() >> 16;
68     } else {
69       streamer.EmitIntValue(b2, 1);
70       w = inst.getSize() >> 3;
71     }
72     streamer.EmitIntValue(w, 2);
73     break;
74   case Win64EH::UOP_AllocSmall:
75     b2 |= (inst.getSize() >> 3) & 0x0F;
76     streamer.EmitIntValue(0, 1);
77     streamer.EmitIntValue(b2, 1);
78     break;
79   case Win64EH::UOP_SetFPReg:
80     b1 = inst.getOffset() & 0xF0;
81     streamer.EmitIntValue(b1, 1);
82     streamer.EmitIntValue(b2, 1);
83     break;
84   case Win64EH::UOP_SaveNonVol:
85   case Win64EH::UOP_SaveXMM128:
86     b2 |= inst.getRegister() & 0x0F;
87     streamer.EmitIntValue(0, 1);
88     streamer.EmitIntValue(b2, 1);
89     w = inst.getOffset() >> 3;
90     if (inst.getOperation() == Win64EH::UOP_SaveXMM128)
91       w >>= 1;
92     streamer.EmitIntValue(w, 2);
93     break;
94   case Win64EH::UOP_SaveNonVolBig:
95   case Win64EH::UOP_SaveXMM128Big:
96     b2 |= inst.getRegister() & 0x0F;
97     streamer.EmitIntValue(0, 1);
98     streamer.EmitIntValue(b2, 1);
99     if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big)
100       w = inst.getOffset() & 0xFFF0;
101     else
102       w = inst.getOffset() & 0xFFF8;
103     streamer.EmitIntValue(w, 2);
104     w = inst.getOffset() >> 16;
105     streamer.EmitIntValue(w, 2);
106     break;
107   case Win64EH::UOP_PushMachFrame:
108     if (inst.isPushCodeFrame())
109       b2 |= 1;
110     streamer.EmitIntValue(0, 1);
111     streamer.EmitIntValue(b2, 1);
112     break;
113   }
114 }
115
116 static void EmitRuntimeFunction(MCStreamer &streamer,
117                                 const MCWin64EHUnwindInfo *info) {
118   MCContext &context = streamer.getContext();
119
120   streamer.EmitValueToAlignment(4);
121   streamer.EmitValue(MCSymbolRefExpr::Create(info->Begin, context), 4);
122   streamer.EmitValue(MCSymbolRefExpr::Create(info->End, context), 4);
123   streamer.EmitValue(MCSymbolRefExpr::Create(info->Symbol, context), 4);
124 }
125
126 static void EmitUnwindInfo(MCStreamer &streamer, MCWin64EHUnwindInfo *info) {
127   // If this UNWIND_INFO already has a symbol, it's already been emitted.
128   if (info->Symbol) return;
129
130   MCContext &context = streamer.getContext();
131   streamer.EmitValueToAlignment(4);
132   // Upper 3 bits are the version number (currently 1).
133   uint8_t flags = 0x20;
134   info->Symbol = context.CreateTempSymbol();
135   streamer.EmitLabel(info->Symbol);
136
137   if (info->ChainedParent)
138     flags |= Win64EH::UNW_ChainInfo;
139   else {
140     if (info->HandlesUnwind)
141       flags |= Win64EH::UNW_TerminateHandler;
142     if (info->HandlesExceptions)
143       flags |= Win64EH::UNW_ExceptionHandler;
144   }
145   streamer.EmitIntValue(flags, 1);
146
147   // Build up the prolog size expression.
148   const MCExpr *prologSize = MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create(
149                                                       info->PrologEnd, context),
150                                                      MCSymbolRefExpr::Create(
151                                                           info->Begin, context),
152                                                      context);
153   streamer.EmitAbsValue(prologSize, 1);
154
155   uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
156   streamer.EmitIntValue(numCodes, 1);
157
158   uint8_t frame = 0;
159   if (info->LastFrameInst >= 0) {
160     MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst];
161     assert(frameInst.getOperation() == Win64EH::UOP_SetFPReg);
162     frame = ((frameInst.getRegister() & 0x0F) << 4) |
163             ((frameInst.getOffset() >> 4) & 0x0F);
164   }
165   streamer.EmitIntValue(frame, 1);
166
167   // Emit unwind instructions (in reverse order).
168   uint8_t numInst = info->Instructions.size();
169   for (uint8_t c = 0; c < numInst; ++c) {
170     MCWin64EHInstruction inst = info->Instructions.back();
171     info->Instructions.pop_back();
172     EmitUnwindCode(streamer, inst);
173   }
174
175   if (flags & Win64EH::UNW_ChainInfo)
176     EmitRuntimeFunction(streamer, info->ChainedParent);
177   else if (flags &(Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler))
178     streamer.EmitValue(MCSymbolRefExpr::Create(info->ExceptionHandler, context),
179                        4);
180 }
181
182 void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer,
183                                             MCWin64EHUnwindInfo *info) {
184   // Switch sections (the static function above is meant to be called from
185   // here and from Emit().
186   MCContext &context = streamer.getContext();
187   const TargetAsmInfo &asmInfo = context.getTargetAsmInfo();
188   const MCSection *xdataSect = asmInfo.getWin64EHTableSection();
189   streamer.SwitchSection(xdataSect);
190
191   llvm::EmitUnwindInfo(streamer, info);
192 }
193
194 void MCWin64EHUnwindEmitter::Emit(MCStreamer &streamer) {
195   MCContext &context = streamer.getContext();
196   // Emit the unwind info structs first.
197   const TargetAsmInfo &asmInfo = context.getTargetAsmInfo();
198   const MCSection *xdataSect = asmInfo.getWin64EHTableSection();
199   streamer.SwitchSection(xdataSect);
200   for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i)
201     llvm::EmitUnwindInfo(streamer, &streamer.getW64UnwindInfo(i));
202   // Now emit RUNTIME_FUNCTION entries.
203   const MCSection *pdataSect = asmInfo.getWin64EHFuncTableSection();
204   streamer.SwitchSection(pdataSect);
205   for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i)
206     EmitRuntimeFunction(streamer, &streamer.getW64UnwindInfo(i));
207 }
208
209 } // End of namespace llvm
210