LLVM  15.0.0git
ARMWinCOFFStreamer.cpp
Go to the documentation of this file.
1 //===-- ARMWinCOFFStreamer.cpp - ARM Target WinCOFF Streamer ----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "ARMMCTargetDesc.h"
10 #include "llvm/MC/MCAsmBackend.h"
11 #include "llvm/MC/MCAssembler.h"
12 #include "llvm/MC/MCCodeEmitter.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCObjectWriter.h"
15 #include "llvm/MC/MCWin64EH.h"
17 
18 using namespace llvm;
19 
20 namespace {
21 class ARMWinCOFFStreamer : public MCWinCOFFStreamer {
23 
24 public:
25  ARMWinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB,
26  std::unique_ptr<MCCodeEmitter> CE,
27  std::unique_ptr<MCObjectWriter> OW)
28  : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {}
29 
30  void emitWinEHHandlerData(SMLoc Loc) override;
31  void emitWindowsUnwindTables() override;
32  void emitWindowsUnwindTables(WinEH::FrameInfo *Frame) override;
33 
34  void emitThumbFunc(MCSymbol *Symbol) override;
35  void finishImpl() override;
36 };
37 
38 void ARMWinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) {
40 
41  // We have to emit the unwind info now, because this directive
42  // actually switches to the .xdata section!
43  EHStreamer.EmitUnwindInfo(*this, getCurrentWinFrameInfo(),
44  /* HandlerData = */ true);
45 }
46 
47 void ARMWinCOFFStreamer::emitWindowsUnwindTables(WinEH::FrameInfo *Frame) {
48  EHStreamer.EmitUnwindInfo(*this, Frame, /* HandlerData = */ false);
49 }
50 
51 void ARMWinCOFFStreamer::emitWindowsUnwindTables() {
52  if (!getNumWinFrameInfos())
53  return;
54  EHStreamer.Emit(*this);
55 }
56 
57 void ARMWinCOFFStreamer::emitThumbFunc(MCSymbol *Symbol) {
58  getAssembler().setIsThumbFunc(Symbol);
59 }
60 
61 void ARMWinCOFFStreamer::finishImpl() {
62  emitFrames(nullptr);
63  emitWindowsUnwindTables();
64 
66 }
67 }
68 
70  MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB,
71  std::unique_ptr<MCObjectWriter> &&OW,
72  std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
73  bool IncrementalLinkerCompatible) {
74  auto *S = new ARMWinCOFFStreamer(Context, std::move(MAB), std::move(Emitter),
75  std::move(OW));
76  S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible);
77  return S;
78 }
79 
80 namespace {
81 class ARMTargetWinCOFFStreamer : public llvm::ARMTargetStreamer {
82 private:
83  // True if we are processing SEH directives in an epilogue.
84  bool InEpilogCFI = false;
85 
86  // Symbol of the current epilog for which we are processing SEH directives.
87  MCSymbol *CurrentEpilog = nullptr;
88 
89 public:
90  ARMTargetWinCOFFStreamer(llvm::MCStreamer &S) : ARMTargetStreamer(S) {}
91 
92  // The unwind codes on ARM Windows are documented at
93  // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
94  void emitARMWinCFIAllocStack(unsigned Size, bool Wide) override;
95  void emitARMWinCFISaveRegMask(unsigned Mask, bool Wide) override;
96  void emitARMWinCFISaveSP(unsigned Reg) override;
97  void emitARMWinCFISaveFRegs(unsigned First, unsigned Last) override;
98  void emitARMWinCFISaveLR(unsigned Offset) override;
99  void emitARMWinCFIPrologEnd(bool Fragment) override;
100  void emitARMWinCFINop(bool Wide) override;
101  void emitARMWinCFIEpilogStart(unsigned Condition) override;
102  void emitARMWinCFIEpilogEnd() override;
103  void emitARMWinCFICustom(unsigned Opcode) override;
104 
105 private:
106  void emitARMWinUnwindCode(unsigned UnwindCode, int Reg, int Offset);
107 };
108 
109 // Helper function to common out unwind code setup for those codes that can
110 // belong to both prolog and epilog.
111 void ARMTargetWinCOFFStreamer::emitARMWinUnwindCode(unsigned UnwindCode,
112  int Reg, int Offset) {
113  auto &S = getStreamer();
114  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
115  if (!CurFrame)
116  return;
117  MCSymbol *Label = S.emitCFILabel();
118  auto Inst = WinEH::Instruction(UnwindCode, Label, Reg, Offset);
119  if (InEpilogCFI)
120  CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
121  else
122  CurFrame->Instructions.push_back(Inst);
123 }
124 
125 void ARMTargetWinCOFFStreamer::emitARMWinCFIAllocStack(unsigned Size,
126  bool Wide) {
127  unsigned Op = Win64EH::UOP_AllocSmall;
128  if (!Wide) {
129  if (Size / 4 > 0xffff)
131  else if (Size / 4 > 0x7f)
133  } else {
135  if (Size / 4 > 0xffff)
137  else if (Size / 4 > 0x3ff)
139  }
140  emitARMWinUnwindCode(Op, -1, Size);
141 }
142 
143 void ARMTargetWinCOFFStreamer::emitARMWinCFISaveRegMask(unsigned Mask,
144  bool Wide) {
145  assert(Mask != 0);
146  int Lr = (Mask & 0x4000) ? 1 : 0;
147  Mask &= ~0x4000;
148  if (Wide)
149  assert((Mask & ~0x1fff) == 0);
150  else
151  assert((Mask & ~0x00ff) == 0);
152  if (Mask && ((Mask + (1 << 4)) & Mask) == 0) {
153  if (Wide && (Mask & 0x1000) == 0 && (Mask & 0xff) == 0xf0) {
154  // One continuous range from r4 to r8-r11
155  for (int I = 11; I >= 8; I--) {
156  if (Mask & (1 << I)) {
157  emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegsR4R11LR, I, Lr);
158  return;
159  }
160  }
161  // If it actually was from r4 to r4-r7, continue below.
162  } else if (!Wide) {
163  // One continuous range from r4 to r4-r7
164  for (int I = 7; I >= 4; I--) {
165  if (Mask & (1 << I)) {
166  emitARMWinUnwindCode(Win64EH::UOP_SaveRegsR4R7LR, I, Lr);
167  return;
168  }
169  }
170  llvm_unreachable("logic error");
171  }
172  }
173  Mask |= Lr << 14;
174  if (Wide)
175  emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegMask, Mask, 0);
176  else
177  emitARMWinUnwindCode(Win64EH::UOP_SaveRegMask, Mask, 0);
178 }
179 
180 void ARMTargetWinCOFFStreamer::emitARMWinCFISaveSP(unsigned Reg) {
181  emitARMWinUnwindCode(Win64EH::UOP_SaveSP, Reg, 0);
182 }
183 
184 void ARMTargetWinCOFFStreamer::emitARMWinCFISaveFRegs(unsigned First,
185  unsigned Last) {
186  assert(First <= Last);
187  assert(First >= 16 || Last < 16);
188  assert(First <= 31 && Last <= 31);
189  if (First == 8)
190  emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD8D15, Last, 0);
191  else if (First <= 15)
192  emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD0D15, First, Last);
193  else
194  emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD16D31, First, Last);
195 }
196 
197 void ARMTargetWinCOFFStreamer::emitARMWinCFISaveLR(unsigned Offset) {
198  emitARMWinUnwindCode(Win64EH::UOP_SaveLR, 0, Offset);
199 }
200 
201 void ARMTargetWinCOFFStreamer::emitARMWinCFINop(bool Wide) {
202  if (Wide)
203  emitARMWinUnwindCode(Win64EH::UOP_WideNop, -1, 0);
204  else
205  emitARMWinUnwindCode(Win64EH::UOP_Nop, -1, 0);
206 }
207 
208 void ARMTargetWinCOFFStreamer::emitARMWinCFIPrologEnd(bool Fragment) {
209  auto &S = getStreamer();
210  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
211  if (!CurFrame)
212  return;
213 
214  MCSymbol *Label = S.emitCFILabel();
215  CurFrame->PrologEnd = Label;
216  WinEH::Instruction Inst =
217  WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
218  auto it = CurFrame->Instructions.begin();
219  CurFrame->Instructions.insert(it, Inst);
220  CurFrame->Fragment = Fragment;
221 }
222 
223 void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogStart(unsigned Condition) {
224  auto &S = getStreamer();
225  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
226  if (!CurFrame)
227  return;
228 
229  InEpilogCFI = true;
230  CurrentEpilog = S.emitCFILabel();
231  CurFrame->EpilogMap[CurrentEpilog].Condition = Condition;
232 }
233 
234 void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogEnd() {
235  auto &S = getStreamer();
236  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
237  if (!CurFrame)
238  return;
239 
240  if (!CurrentEpilog) {
241  S.getContext().reportError(SMLoc(), "Stray .seh_endepilogue in " +
242  CurFrame->Function->getName());
243  return;
244  }
245 
246  std::vector<WinEH::Instruction> &Epilog =
247  CurFrame->EpilogMap[CurrentEpilog].Instructions;
248 
249  unsigned UnwindCode = Win64EH::UOP_End;
250  if (!Epilog.empty()) {
251  WinEH::Instruction EndInstr = Epilog.back();
252  if (EndInstr.Operation == Win64EH::UOP_Nop) {
253  UnwindCode = Win64EH::UOP_EndNop;
254  Epilog.pop_back();
255  } else if (EndInstr.Operation == Win64EH::UOP_WideNop) {
256  UnwindCode = Win64EH::UOP_WideEndNop;
257  Epilog.pop_back();
258  }
259  }
260 
261  InEpilogCFI = false;
262  WinEH::Instruction Inst = WinEH::Instruction(UnwindCode, nullptr, -1, 0);
263  CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
264  MCSymbol *Label = S.emitCFILabel();
265  CurFrame->EpilogMap[CurrentEpilog].End = Label;
266  CurrentEpilog = nullptr;
267 }
268 
269 void ARMTargetWinCOFFStreamer::emitARMWinCFICustom(unsigned Opcode) {
270  emitARMWinUnwindCode(Win64EH::UOP_Custom, 0, Opcode);
271 }
272 
273 } // end anonymous namespace
274 
276  return new ARMTargetWinCOFFStreamer(S);
277 }
llvm::MCWinCOFFStreamer
Definition: MCWinCOFFStreamer.h:27
llvm::Win64EH::UOP_SaveFRegD0D15
@ UOP_SaveFRegD0D15
Definition: Win64EH.h:85
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::createARMObjectTargetWinCOFFStreamer
MCTargetStreamer * createARMObjectTargetWinCOFFStreamer(MCStreamer &S)
Definition: ARMWinCOFFStreamer.cpp:275
llvm::MCSymbol
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
it
into xmm2 addss xmm2 xmm1 xmm3 addss xmm3 movaps xmm0 unpcklps xmm0 ret seems silly when it could just be one addps Expand libm rounding functions main should enable SSE DAZ mode and other fast SSE modes Think about doing i64 math in SSE regs on x86 This testcase should have no SSE instructions in it
Definition: README-SSE.txt:81
ARMMCTargetDesc.h
llvm::MCContext
Context object for machine code objects.
Definition: MCContext.h:76
llvm::EHStreamer
Emits exception handling directives.
Definition: EHStreamer.h:30
llvm::ARMTargetStreamer
Definition: MCStreamer.h:135
MCCodeEmitter.h
llvm::X86Disassembler::Reg
Reg
All possible values of the reg field in the ModR/M byte.
Definition: X86DisassemblerDecoder.h:462
llvm::X86::SecondMacroFusionInstKind::AB
@ AB
MCAssembler.h
llvm::Win64EH::ARMUnwindEmitter
Definition: MCWin64EH.h:60
llvm::Win64EH::UOP_WideNop
@ UOP_WideNop
Definition: Win64EH.h:88
llvm::Win64EH::UOP_EndNop
@ UOP_EndNop
Definition: Win64EH.h:90
llvm::Win64EH::UOP_SaveRegsR4R7LR
@ UOP_SaveRegsR4R7LR
Definition: Win64EH.h:80
llvm::Win64EH::UOP_Nop
@ UOP_Nop
Definition: Win64EH.h:58
llvm::WinEH::FrameInfo::EpilogMap
MapVector< MCSymbol *, Epilog > EpilogMap
Definition: MCWinEH.h:63
Context
LLVMContext & Context
Definition: NVVMIntrRange.cpp:66
llvm::BitmaskEnumDetail::Mask
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
Definition: BitmaskEnum.h:80
llvm::MCStreamer
Streaming machine code generation interface.
Definition: MCStreamer.h:212
llvm::Win64EH::UOP_SaveSP
@ UOP_SaveSP
Definition: Win64EH.h:79
MCAsmBackend.h
llvm::SMLoc
Represents a location in source code.
Definition: SMLoc.h:23
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
MCContext.h
llvm::SPIRV::ExecutionModel::Fragment
@ Fragment
llvm::Win64EH::UOP_WideAllocMedium
@ UOP_WideAllocMedium
Definition: Win64EH.h:74
llvm::MCStreamer::emitWinEHHandlerData
virtual void emitWinEHHandlerData(SMLoc Loc=SMLoc())
Definition: MCStreamer.cpp:800
llvm::Win64EH::UOP_WideSaveRegsR4R11LR
@ UOP_WideSaveRegsR4R11LR
Definition: Win64EH.h:81
llvm::MCTargetStreamer
Target specific streamer interface.
Definition: MCStreamer.h:93
llvm::Win64EH::UOP_WideAllocHuge
@ UOP_WideAllocHuge
Definition: Win64EH.h:76
llvm::MCSymbol::getName
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:198
llvm::WinEH::FrameInfo::Fragment
bool Fragment
Definition: MCWinEH.h:53
llvm::WinEH::FrameInfo::Function
const MCSymbol * Function
Definition: MCWinEH.h:44
llvm::Win64EH::UOP_End
@ UOP_End
Definition: Win64EH.h:59
llvm::Win64EH::UOP_AllocSmall
@ UOP_AllocSmall
Definition: Win64EH.h:32
llvm::Win64EH::UOP_WideSaveRegMask
@ UOP_WideSaveRegMask
Definition: Win64EH.h:78
llvm::Win64EH::UOP_AllocHuge
@ UOP_AllocHuge
Definition: Win64EH.h:73
llvm::WinEH::FrameInfo::PrologEnd
const MCSymbol * PrologEnd
Definition: MCWinEH.h:45
llvm::Win64EH::UOP_SaveFRegD16D31
@ UOP_SaveFRegD16D31
Definition: Win64EH.h:86
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::WinEH::Instruction::Operation
unsigned Operation
Definition: MCWinEH.h:25
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::move
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1675
llvm::WinEH::EncodingType::CE
@ CE
Windows NT (Windows on ARM)
llvm::Win64EH::UOP_SaveLR
@ UOP_SaveLR
Definition: Win64EH.h:84
llvm::MCWinCOFFStreamer::finishImpl
void finishImpl() override
Streamer specific finalization.
Definition: MCWinCOFFStreamer.cpp:363
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
S
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
Definition: README.txt:210
MCWinCOFFStreamer.h
llvm::createARMWinCOFFStreamer
MCStreamer * createARMWinCOFFStreamer(MCContext &Context, std::unique_ptr< MCAsmBackend > &&MAB, std::unique_ptr< MCObjectWriter > &&OW, std::unique_ptr< MCCodeEmitter > &&Emitter, bool RelaxAll, bool IncrementalLinkerCompatible)
Definition: ARMWinCOFFStreamer.cpp:69
MCObjectWriter.h
llvm::pdb::PDB_SymType::Label
@ Label
std
Definition: BitVector.h:851
llvm::Win64EH::UOP_Custom
@ UOP_Custom
Definition: Win64EH.h:94
Epilog
@ Epilog
Definition: AArch64LowerHomogeneousPrologEpilog.cpp:125
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:345
llvm::Win64EH::UOP_SaveFRegD8D15
@ UOP_SaveFRegD8D15
Definition: Win64EH.h:82
llvm::WinEH::FrameInfo
Definition: MCWinEH.h:39
llvm::ARMBuildAttrs::Symbol
@ Symbol
Definition: ARMBuildAttributes.h:83
llvm::WinEH::Instruction
Definition: MCWinEH.h:21
llvm::Win64EH::UOP_WideAllocLarge
@ UOP_WideAllocLarge
Definition: Win64EH.h:75
llvm::WinEH::FrameInfo::Instructions
std::vector< Instruction > Instructions
Definition: MCWinEH.h:57
llvm::Win64EH::UOP_WideEndNop
@ UOP_WideEndNop
Definition: Win64EH.h:91
MCWin64EH.h
llvm::Win64EH::UOP_SaveRegMask
@ UOP_SaveRegMask
Definition: Win64EH.h:83
llvm::Win64EH::UOP_AllocLarge
@ UOP_AllocLarge
Definition: Win64EH.h:31