/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- WebAssemblyInstrInfo.cpp - WebAssembly Instruction Information ----===// |
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 | | /// \file |
10 | | /// This file contains the WebAssembly implementation of the |
11 | | /// TargetInstrInfo class. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "WebAssemblyInstrInfo.h" |
16 | | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" |
17 | | #include "WebAssemblyMachineFunctionInfo.h" |
18 | | #include "WebAssemblySubtarget.h" |
19 | | #include "llvm/CodeGen/MachineFrameInfo.h" |
20 | | #include "llvm/CodeGen/MachineInstrBuilder.h" |
21 | | #include "llvm/CodeGen/MachineMemOperand.h" |
22 | | #include "llvm/CodeGen/MachineRegisterInfo.h" |
23 | | using namespace llvm; |
24 | | |
25 | | #define DEBUG_TYPE "wasm-instr-info" |
26 | | |
27 | | #define GET_INSTRINFO_CTOR_DTOR |
28 | | #include "WebAssemblyGenInstrInfo.inc" |
29 | | |
30 | | // defines WebAssembly::getNamedOperandIdx |
31 | | #define GET_INSTRINFO_NAMED_OPS |
32 | | #include "WebAssemblyGenInstrInfo.inc" |
33 | | |
34 | | WebAssemblyInstrInfo::WebAssemblyInstrInfo(const WebAssemblySubtarget &STI) |
35 | | : WebAssemblyGenInstrInfo(WebAssembly::ADJCALLSTACKDOWN, |
36 | | WebAssembly::ADJCALLSTACKUP, |
37 | | WebAssembly::CATCHRET), |
38 | 546 | RI(STI.getTargetTriple()) {} |
39 | | |
40 | | bool WebAssemblyInstrInfo::isReallyTriviallyReMaterializable( |
41 | 4.05k | const MachineInstr &MI, AliasAnalysis *AA) const { |
42 | 4.05k | switch (MI.getOpcode()) { |
43 | 4.05k | case WebAssembly::CONST_I32: |
44 | 4.05k | case WebAssembly::CONST_I64: |
45 | 4.05k | case WebAssembly::CONST_F32: |
46 | 4.05k | case WebAssembly::CONST_F64: |
47 | 4.05k | // isReallyTriviallyReMaterializableGeneric misses these because of the |
48 | 4.05k | // ARGUMENTS implicit def, so we manualy override it here. |
49 | 4.05k | return true; |
50 | 4.05k | default: |
51 | 0 | return false; |
52 | 4.05k | } |
53 | 4.05k | } |
54 | | |
55 | | void WebAssemblyInstrInfo::copyPhysReg(MachineBasicBlock &MBB, |
56 | | MachineBasicBlock::iterator I, |
57 | | const DebugLoc &DL, unsigned DestReg, |
58 | 126 | unsigned SrcReg, bool KillSrc) const { |
59 | 126 | // This method is called by post-RA expansion, which expects only pregs to |
60 | 126 | // exist. However we need to handle both here. |
61 | 126 | auto &MRI = MBB.getParent()->getRegInfo(); |
62 | 126 | const TargetRegisterClass *RC = |
63 | 126 | TargetRegisterInfo::isVirtualRegister(DestReg) |
64 | 126 | ? MRI.getRegClass(DestReg)108 |
65 | 126 | : MRI.getTargetRegisterInfo()->getMinimalPhysRegClass(DestReg)18 ; |
66 | 126 | |
67 | 126 | unsigned CopyOpcode; |
68 | 126 | if (RC == &WebAssembly::I32RegClass) |
69 | 103 | CopyOpcode = WebAssembly::COPY_I32; |
70 | 23 | else if (RC == &WebAssembly::I64RegClass) |
71 | 7 | CopyOpcode = WebAssembly::COPY_I64; |
72 | 16 | else if (RC == &WebAssembly::F32RegClass) |
73 | 1 | CopyOpcode = WebAssembly::COPY_F32; |
74 | 15 | else if (RC == &WebAssembly::F64RegClass) |
75 | 13 | CopyOpcode = WebAssembly::COPY_F64; |
76 | 2 | else if (RC == &WebAssembly::V128RegClass) |
77 | 1 | CopyOpcode = WebAssembly::COPY_V128; |
78 | 1 | else if (RC == &WebAssembly::EXNREFRegClass) |
79 | 1 | CopyOpcode = WebAssembly::COPY_EXNREF; |
80 | 1 | else |
81 | 1 | llvm_unreachable0 ("Unexpected register class"); |
82 | 126 | |
83 | 126 | BuildMI(MBB, I, DL, get(CopyOpcode), DestReg) |
84 | 126 | .addReg(SrcReg, KillSrc ? RegState::Kill0 : 0); |
85 | 126 | } |
86 | | |
87 | | MachineInstr *WebAssemblyInstrInfo::commuteInstructionImpl( |
88 | 11.6k | MachineInstr &MI, bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const { |
89 | 11.6k | // If the operands are stackified, we can't reorder them. |
90 | 11.6k | WebAssemblyFunctionInfo &MFI = |
91 | 11.6k | *MI.getParent()->getParent()->getInfo<WebAssemblyFunctionInfo>(); |
92 | 11.6k | if (MFI.isVRegStackified(MI.getOperand(OpIdx1).getReg()) || |
93 | 11.6k | MFI.isVRegStackified(MI.getOperand(OpIdx2).getReg())) |
94 | 0 | return nullptr; |
95 | 11.6k | |
96 | 11.6k | // Otherwise use the default implementation. |
97 | 11.6k | return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2); |
98 | 11.6k | } |
99 | | |
100 | | // Branch analysis. |
101 | | bool WebAssemblyInstrInfo::analyzeBranch(MachineBasicBlock &MBB, |
102 | | MachineBasicBlock *&TBB, |
103 | | MachineBasicBlock *&FBB, |
104 | | SmallVectorImpl<MachineOperand> &Cond, |
105 | 95.1k | bool /*AllowModify*/) const { |
106 | 95.1k | const auto &MFI = *MBB.getParent()->getInfo<WebAssemblyFunctionInfo>(); |
107 | 95.1k | // WebAssembly has control flow that doesn't have explicit branches or direct |
108 | 95.1k | // fallthrough (e.g. try/catch), which can't be modeled by analyzeBranch. It |
109 | 95.1k | // is created after CFGStackify. |
110 | 95.1k | if (MFI.isCFGStackified()) |
111 | 14.5k | return true; |
112 | 80.5k | |
113 | 80.5k | bool HaveCond = false; |
114 | 80.5k | for (MachineInstr &MI : MBB.terminators()) { |
115 | 78.2k | switch (MI.getOpcode()) { |
116 | 78.2k | default: |
117 | 65.8k | // Unhandled instruction; bail out. |
118 | 65.8k | return true; |
119 | 78.2k | case WebAssembly::BR_IF: |
120 | 5.06k | if (HaveCond) |
121 | 0 | return true; |
122 | 5.06k | Cond.push_back(MachineOperand::CreateImm(true)); |
123 | 5.06k | Cond.push_back(MI.getOperand(1)); |
124 | 5.06k | TBB = MI.getOperand(0).getMBB(); |
125 | 5.06k | HaveCond = true; |
126 | 5.06k | break; |
127 | 5.06k | case WebAssembly::BR_UNLESS: |
128 | 1.23k | if (HaveCond) |
129 | 0 | return true; |
130 | 1.23k | Cond.push_back(MachineOperand::CreateImm(false)); |
131 | 1.23k | Cond.push_back(MI.getOperand(1)); |
132 | 1.23k | TBB = MI.getOperand(0).getMBB(); |
133 | 1.23k | HaveCond = true; |
134 | 1.23k | break; |
135 | 5.82k | case WebAssembly::BR: |
136 | 5.82k | if (!HaveCond) |
137 | 3.33k | TBB = MI.getOperand(0).getMBB(); |
138 | 2.48k | else |
139 | 2.48k | FBB = MI.getOperand(0).getMBB(); |
140 | 5.82k | break; |
141 | 1.23k | case WebAssembly::BR_ON_EXN: |
142 | 232 | if (HaveCond) |
143 | 0 | return true; |
144 | 232 | Cond.push_back(MachineOperand::CreateImm(true)); |
145 | 232 | Cond.push_back(MI.getOperand(2)); |
146 | 232 | TBB = MI.getOperand(0).getMBB(); |
147 | 232 | HaveCond = true; |
148 | 232 | break; |
149 | 12.3k | } |
150 | 12.3k | if (MI.isBarrier()) |
151 | 5.82k | break; |
152 | 12.3k | } |
153 | 80.5k | |
154 | 80.5k | return false14.6k ; |
155 | 80.5k | } |
156 | | |
157 | | unsigned WebAssemblyInstrInfo::removeBranch(MachineBasicBlock &MBB, |
158 | 799 | int *BytesRemoved) const { |
159 | 799 | assert(!BytesRemoved && "code size not handled"); |
160 | 799 | |
161 | 799 | MachineBasicBlock::instr_iterator I = MBB.instr_end(); |
162 | 799 | unsigned Count = 0; |
163 | 799 | |
164 | 1.88k | while (I != MBB.instr_begin()) { |
165 | 1.79k | --I; |
166 | 1.79k | if (I->isDebugInstr()) |
167 | 12 | continue; |
168 | 1.78k | if (!I->isTerminator()) |
169 | 713 | break; |
170 | 1.07k | // Remove the branch. |
171 | 1.07k | I->eraseFromParent(); |
172 | 1.07k | I = MBB.instr_end(); |
173 | 1.07k | ++Count; |
174 | 1.07k | } |
175 | 799 | |
176 | 799 | return Count; |
177 | 799 | } |
178 | | |
179 | | unsigned WebAssemblyInstrInfo::insertBranch( |
180 | | MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, |
181 | 734 | ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { |
182 | 734 | assert(!BytesAdded && "code size not handled"); |
183 | 734 | |
184 | 734 | if (Cond.empty()) { |
185 | 260 | if (!TBB) |
186 | 0 | return 0; |
187 | 260 | |
188 | 260 | BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(TBB); |
189 | 260 | return 1; |
190 | 260 | } |
191 | 474 | |
192 | 474 | assert(Cond.size() == 2 && "Expected a flag and a successor block"); |
193 | 474 | |
194 | 474 | MachineFunction &MF = *MBB.getParent(); |
195 | 474 | auto &MRI = MF.getRegInfo(); |
196 | 474 | bool IsBrOnExn = Cond[1].isReg() && MRI.getRegClass(Cond[1].getReg()) == |
197 | 474 | &WebAssembly::EXNREFRegClass; |
198 | 474 | |
199 | 474 | if (Cond[0].getImm()) { |
200 | 271 | if (IsBrOnExn) { |
201 | 41 | const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception"); |
202 | 41 | BuildMI(&MBB, DL, get(WebAssembly::BR_ON_EXN)) |
203 | 41 | .addMBB(TBB) |
204 | 41 | .addExternalSymbol(CPPExnSymbol) |
205 | 41 | .add(Cond[1]); |
206 | 41 | } else |
207 | 230 | BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]); |
208 | 271 | } else { |
209 | 203 | assert(!IsBrOnExn && "br_on_exn does not have a reversed condition"); |
210 | 203 | BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]); |
211 | 203 | } |
212 | 474 | if (!FBB) |
213 | 460 | return 1; |
214 | 14 | |
215 | 14 | BuildMI(&MBB, DL, get(WebAssembly::BR)).addMBB(FBB); |
216 | 14 | return 2; |
217 | 14 | } |
218 | | |
219 | | bool WebAssemblyInstrInfo::reverseBranchCondition( |
220 | 289 | SmallVectorImpl<MachineOperand> &Cond) const { |
221 | 289 | assert(Cond.size() == 2 && "Expected a flag and a condition expression"); |
222 | 289 | |
223 | 289 | // br_on_exn's condition cannot be reversed |
224 | 289 | MachineFunction &MF = *Cond[1].getParent()->getParent()->getParent(); |
225 | 289 | auto &MRI = MF.getRegInfo(); |
226 | 289 | if (Cond[1].isReg() && |
227 | 289 | MRI.getRegClass(Cond[1].getReg()) == &WebAssembly::EXNREFRegClass) |
228 | 0 | return true; |
229 | 289 | |
230 | 289 | Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm()); |
231 | 289 | return false; |
232 | 289 | } |