Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
35266 views
1
//===-- WebAssemblyFastISel.cpp - WebAssembly FastISel implementation -----===//
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 defines the WebAssembly-specific support for the FastISel
11
/// class. Some of the target-specific code is generated by tablegen in the file
12
/// WebAssemblyGenFastISel.inc, which is #included here.
13
///
14
/// TODO: kill flags
15
///
16
//===----------------------------------------------------------------------===//
17
18
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19
#include "Utils/WebAssemblyTypeUtilities.h"
20
#include "WebAssembly.h"
21
#include "WebAssemblyMachineFunctionInfo.h"
22
#include "WebAssemblySubtarget.h"
23
#include "WebAssemblyTargetMachine.h"
24
#include "WebAssemblyUtilities.h"
25
#include "llvm/Analysis/BranchProbabilityInfo.h"
26
#include "llvm/CodeGen/FastISel.h"
27
#include "llvm/CodeGen/FunctionLoweringInfo.h"
28
#include "llvm/CodeGen/MachineConstantPool.h"
29
#include "llvm/CodeGen/MachineFrameInfo.h"
30
#include "llvm/CodeGen/MachineInstrBuilder.h"
31
#include "llvm/CodeGen/MachineModuleInfo.h"
32
#include "llvm/CodeGen/MachineRegisterInfo.h"
33
#include "llvm/IR/DataLayout.h"
34
#include "llvm/IR/DerivedTypes.h"
35
#include "llvm/IR/Function.h"
36
#include "llvm/IR/GetElementPtrTypeIterator.h"
37
#include "llvm/IR/GlobalAlias.h"
38
#include "llvm/IR/GlobalVariable.h"
39
#include "llvm/IR/Instructions.h"
40
#include "llvm/IR/IntrinsicInst.h"
41
#include "llvm/IR/Operator.h"
42
#include "llvm/IR/PatternMatch.h"
43
44
using namespace llvm;
45
using namespace PatternMatch;
46
47
#define DEBUG_TYPE "wasm-fastisel"
48
49
namespace {
50
51
class WebAssemblyFastISel final : public FastISel {
52
// All possible address modes.
53
class Address {
54
public:
55
using BaseKind = enum { RegBase, FrameIndexBase };
56
57
private:
58
BaseKind Kind = RegBase;
59
union {
60
unsigned Reg;
61
int FI;
62
} Base;
63
64
// Whether the base has been determined yet
65
bool IsBaseSet = false;
66
67
int64_t Offset = 0;
68
69
const GlobalValue *GV = nullptr;
70
71
public:
72
// Innocuous defaults for our address.
73
Address() { Base.Reg = 0; }
74
void setKind(BaseKind K) {
75
assert(!isSet() && "Can't change kind with non-zero base");
76
Kind = K;
77
}
78
BaseKind getKind() const { return Kind; }
79
bool isRegBase() const { return Kind == RegBase; }
80
bool isFIBase() const { return Kind == FrameIndexBase; }
81
void setReg(unsigned Reg) {
82
assert(isRegBase() && "Invalid base register access!");
83
assert(!IsBaseSet && "Base cannot be reset");
84
Base.Reg = Reg;
85
IsBaseSet = true;
86
}
87
unsigned getReg() const {
88
assert(isRegBase() && "Invalid base register access!");
89
return Base.Reg;
90
}
91
void setFI(unsigned FI) {
92
assert(isFIBase() && "Invalid base frame index access!");
93
assert(!IsBaseSet && "Base cannot be reset");
94
Base.FI = FI;
95
IsBaseSet = true;
96
}
97
unsigned getFI() const {
98
assert(isFIBase() && "Invalid base frame index access!");
99
return Base.FI;
100
}
101
102
void setOffset(int64_t NewOffset) {
103
assert(NewOffset >= 0 && "Offsets must be non-negative");
104
Offset = NewOffset;
105
}
106
int64_t getOffset() const { return Offset; }
107
void setGlobalValue(const GlobalValue *G) { GV = G; }
108
const GlobalValue *getGlobalValue() const { return GV; }
109
bool isSet() const { return IsBaseSet; }
110
};
111
112
/// Keep a pointer to the WebAssemblySubtarget around so that we can make the
113
/// right decision when generating code for different targets.
114
const WebAssemblySubtarget *Subtarget;
115
LLVMContext *Context;
116
117
private:
118
// Utility helper routines
119
MVT::SimpleValueType getSimpleType(Type *Ty) {
120
EVT VT = TLI.getValueType(DL, Ty, /*AllowUnknown=*/true);
121
return VT.isSimple() ? VT.getSimpleVT().SimpleTy
122
: MVT::INVALID_SIMPLE_VALUE_TYPE;
123
}
124
MVT::SimpleValueType getLegalType(MVT::SimpleValueType VT) {
125
switch (VT) {
126
case MVT::i1:
127
case MVT::i8:
128
case MVT::i16:
129
return MVT::i32;
130
case MVT::i32:
131
case MVT::i64:
132
case MVT::f32:
133
case MVT::f64:
134
return VT;
135
case MVT::funcref:
136
case MVT::externref:
137
if (Subtarget->hasReferenceTypes())
138
return VT;
139
break;
140
case MVT::exnref:
141
if (Subtarget->hasReferenceTypes() && Subtarget->hasExceptionHandling())
142
return VT;
143
break;
144
case MVT::f16:
145
return MVT::f32;
146
case MVT::v16i8:
147
case MVT::v8i16:
148
case MVT::v4i32:
149
case MVT::v4f32:
150
case MVT::v2i64:
151
case MVT::v2f64:
152
if (Subtarget->hasSIMD128())
153
return VT;
154
break;
155
default:
156
break;
157
}
158
return MVT::INVALID_SIMPLE_VALUE_TYPE;
159
}
160
bool computeAddress(const Value *Obj, Address &Addr);
161
void materializeLoadStoreOperands(Address &Addr);
162
void addLoadStoreOperands(const Address &Addr, const MachineInstrBuilder &MIB,
163
MachineMemOperand *MMO);
164
unsigned maskI1Value(unsigned Reg, const Value *V);
165
unsigned getRegForI1Value(const Value *V, const BasicBlock *BB, bool &Not);
166
unsigned zeroExtendToI32(unsigned Reg, const Value *V,
167
MVT::SimpleValueType From);
168
unsigned signExtendToI32(unsigned Reg, const Value *V,
169
MVT::SimpleValueType From);
170
unsigned zeroExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
171
MVT::SimpleValueType To);
172
unsigned signExtend(unsigned Reg, const Value *V, MVT::SimpleValueType From,
173
MVT::SimpleValueType To);
174
unsigned getRegForUnsignedValue(const Value *V);
175
unsigned getRegForSignedValue(const Value *V);
176
unsigned getRegForPromotedValue(const Value *V, bool IsSigned);
177
unsigned notValue(unsigned Reg);
178
unsigned copyValue(unsigned Reg);
179
180
// Backend specific FastISel code.
181
unsigned fastMaterializeAlloca(const AllocaInst *AI) override;
182
unsigned fastMaterializeConstant(const Constant *C) override;
183
bool fastLowerArguments() override;
184
185
// Selection routines.
186
bool selectCall(const Instruction *I);
187
bool selectSelect(const Instruction *I);
188
bool selectTrunc(const Instruction *I);
189
bool selectZExt(const Instruction *I);
190
bool selectSExt(const Instruction *I);
191
bool selectICmp(const Instruction *I);
192
bool selectFCmp(const Instruction *I);
193
bool selectBitCast(const Instruction *I);
194
bool selectLoad(const Instruction *I);
195
bool selectStore(const Instruction *I);
196
bool selectBr(const Instruction *I);
197
bool selectRet(const Instruction *I);
198
bool selectUnreachable(const Instruction *I);
199
200
public:
201
// Backend specific FastISel code.
202
WebAssemblyFastISel(FunctionLoweringInfo &FuncInfo,
203
const TargetLibraryInfo *LibInfo)
204
: FastISel(FuncInfo, LibInfo, /*SkipTargetIndependentISel=*/true) {
205
Subtarget = &FuncInfo.MF->getSubtarget<WebAssemblySubtarget>();
206
Context = &FuncInfo.Fn->getContext();
207
}
208
209
bool fastSelectInstruction(const Instruction *I) override;
210
211
#include "WebAssemblyGenFastISel.inc"
212
};
213
214
} // end anonymous namespace
215
216
bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) {
217
const User *U = nullptr;
218
unsigned Opcode = Instruction::UserOp1;
219
if (const auto *I = dyn_cast<Instruction>(Obj)) {
220
// Don't walk into other basic blocks unless the object is an alloca from
221
// another block, otherwise it may not have a virtual register assigned.
222
if (FuncInfo.StaticAllocaMap.count(static_cast<const AllocaInst *>(Obj)) ||
223
FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
224
Opcode = I->getOpcode();
225
U = I;
226
}
227
} else if (const auto *C = dyn_cast<ConstantExpr>(Obj)) {
228
Opcode = C->getOpcode();
229
U = C;
230
}
231
232
if (auto *Ty = dyn_cast<PointerType>(Obj->getType()))
233
if (Ty->getAddressSpace() > 255)
234
// Fast instruction selection doesn't support the special
235
// address spaces.
236
return false;
237
238
if (const auto *GV = dyn_cast<GlobalValue>(Obj)) {
239
if (TLI.isPositionIndependent())
240
return false;
241
if (Addr.getGlobalValue())
242
return false;
243
if (GV->isThreadLocal())
244
return false;
245
Addr.setGlobalValue(GV);
246
return true;
247
}
248
249
switch (Opcode) {
250
default:
251
break;
252
case Instruction::BitCast: {
253
// Look through bitcasts.
254
return computeAddress(U->getOperand(0), Addr);
255
}
256
case Instruction::IntToPtr: {
257
// Look past no-op inttoptrs.
258
if (TLI.getValueType(DL, U->getOperand(0)->getType()) ==
259
TLI.getPointerTy(DL))
260
return computeAddress(U->getOperand(0), Addr);
261
break;
262
}
263
case Instruction::PtrToInt: {
264
// Look past no-op ptrtoints.
265
if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL))
266
return computeAddress(U->getOperand(0), Addr);
267
break;
268
}
269
case Instruction::GetElementPtr: {
270
Address SavedAddr = Addr;
271
uint64_t TmpOffset = Addr.getOffset();
272
// Non-inbounds geps can wrap; wasm's offsets can't.
273
if (!cast<GEPOperator>(U)->isInBounds())
274
goto unsupported_gep;
275
// Iterate through the GEP folding the constants into offsets where
276
// we can.
277
for (gep_type_iterator GTI = gep_type_begin(U), E = gep_type_end(U);
278
GTI != E; ++GTI) {
279
const Value *Op = GTI.getOperand();
280
if (StructType *STy = GTI.getStructTypeOrNull()) {
281
const StructLayout *SL = DL.getStructLayout(STy);
282
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
283
TmpOffset += SL->getElementOffset(Idx);
284
} else {
285
uint64_t S = GTI.getSequentialElementStride(DL);
286
for (;;) {
287
if (const auto *CI = dyn_cast<ConstantInt>(Op)) {
288
// Constant-offset addressing.
289
TmpOffset += CI->getSExtValue() * S;
290
break;
291
}
292
if (S == 1 && Addr.isRegBase() && Addr.getReg() == 0) {
293
// An unscaled add of a register. Set it as the new base.
294
Register Reg = getRegForValue(Op);
295
if (Reg == 0)
296
return false;
297
Addr.setReg(Reg);
298
break;
299
}
300
if (canFoldAddIntoGEP(U, Op)) {
301
// A compatible add with a constant operand. Fold the constant.
302
auto *CI = cast<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
303
TmpOffset += CI->getSExtValue() * S;
304
// Iterate on the other operand.
305
Op = cast<AddOperator>(Op)->getOperand(0);
306
continue;
307
}
308
// Unsupported
309
goto unsupported_gep;
310
}
311
}
312
}
313
// Don't fold in negative offsets.
314
if (int64_t(TmpOffset) >= 0) {
315
// Try to grab the base operand now.
316
Addr.setOffset(TmpOffset);
317
if (computeAddress(U->getOperand(0), Addr))
318
return true;
319
}
320
// We failed, restore everything and try the other options.
321
Addr = SavedAddr;
322
unsupported_gep:
323
break;
324
}
325
case Instruction::Alloca: {
326
const auto *AI = cast<AllocaInst>(Obj);
327
DenseMap<const AllocaInst *, int>::iterator SI =
328
FuncInfo.StaticAllocaMap.find(AI);
329
if (SI != FuncInfo.StaticAllocaMap.end()) {
330
if (Addr.isSet()) {
331
return false;
332
}
333
Addr.setKind(Address::FrameIndexBase);
334
Addr.setFI(SI->second);
335
return true;
336
}
337
break;
338
}
339
case Instruction::Add: {
340
// Adds of constants are common and easy enough.
341
const Value *LHS = U->getOperand(0);
342
const Value *RHS = U->getOperand(1);
343
344
if (isa<ConstantInt>(LHS))
345
std::swap(LHS, RHS);
346
347
if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
348
uint64_t TmpOffset = Addr.getOffset() + CI->getSExtValue();
349
if (int64_t(TmpOffset) >= 0) {
350
Addr.setOffset(TmpOffset);
351
return computeAddress(LHS, Addr);
352
}
353
}
354
355
Address Backup = Addr;
356
if (computeAddress(LHS, Addr) && computeAddress(RHS, Addr))
357
return true;
358
Addr = Backup;
359
360
break;
361
}
362
case Instruction::Sub: {
363
// Subs of constants are common and easy enough.
364
const Value *LHS = U->getOperand(0);
365
const Value *RHS = U->getOperand(1);
366
367
if (const auto *CI = dyn_cast<ConstantInt>(RHS)) {
368
int64_t TmpOffset = Addr.getOffset() - CI->getSExtValue();
369
if (TmpOffset >= 0) {
370
Addr.setOffset(TmpOffset);
371
return computeAddress(LHS, Addr);
372
}
373
}
374
break;
375
}
376
}
377
if (Addr.isSet()) {
378
return false;
379
}
380
Register Reg = getRegForValue(Obj);
381
if (Reg == 0)
382
return false;
383
Addr.setReg(Reg);
384
return Addr.getReg() != 0;
385
}
386
387
void WebAssemblyFastISel::materializeLoadStoreOperands(Address &Addr) {
388
if (Addr.isRegBase()) {
389
unsigned Reg = Addr.getReg();
390
if (Reg == 0) {
391
Reg = createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
392
: &WebAssembly::I32RegClass);
393
unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
394
: WebAssembly::CONST_I32;
395
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Reg)
396
.addImm(0);
397
Addr.setReg(Reg);
398
}
399
}
400
}
401
402
void WebAssemblyFastISel::addLoadStoreOperands(const Address &Addr,
403
const MachineInstrBuilder &MIB,
404
MachineMemOperand *MMO) {
405
// Set the alignment operand (this is rewritten in SetP2AlignOperands).
406
// TODO: Disable SetP2AlignOperands for FastISel and just do it here.
407
MIB.addImm(0);
408
409
if (const GlobalValue *GV = Addr.getGlobalValue())
410
MIB.addGlobalAddress(GV, Addr.getOffset());
411
else
412
MIB.addImm(Addr.getOffset());
413
414
if (Addr.isRegBase())
415
MIB.addReg(Addr.getReg());
416
else
417
MIB.addFrameIndex(Addr.getFI());
418
419
MIB.addMemOperand(MMO);
420
}
421
422
unsigned WebAssemblyFastISel::maskI1Value(unsigned Reg, const Value *V) {
423
return zeroExtendToI32(Reg, V, MVT::i1);
424
}
425
426
unsigned WebAssemblyFastISel::getRegForI1Value(const Value *V,
427
const BasicBlock *BB,
428
bool &Not) {
429
if (const auto *ICmp = dyn_cast<ICmpInst>(V))
430
if (const ConstantInt *C = dyn_cast<ConstantInt>(ICmp->getOperand(1)))
431
if (ICmp->isEquality() && C->isZero() && C->getType()->isIntegerTy(32) &&
432
ICmp->getParent() == BB) {
433
Not = ICmp->isTrueWhenEqual();
434
return getRegForValue(ICmp->getOperand(0));
435
}
436
437
Not = false;
438
Register Reg = getRegForValue(V);
439
if (Reg == 0)
440
return 0;
441
return maskI1Value(Reg, V);
442
}
443
444
unsigned WebAssemblyFastISel::zeroExtendToI32(unsigned Reg, const Value *V,
445
MVT::SimpleValueType From) {
446
if (Reg == 0)
447
return 0;
448
449
switch (From) {
450
case MVT::i1:
451
// If the value is naturally an i1, we don't need to mask it. We only know
452
// if a value is naturally an i1 if it is definitely lowered by FastISel,
453
// not a DAG ISel fallback.
454
if (V != nullptr && isa<Argument>(V) && cast<Argument>(V)->hasZExtAttr())
455
return copyValue(Reg);
456
break;
457
case MVT::i8:
458
case MVT::i16:
459
break;
460
case MVT::i32:
461
return copyValue(Reg);
462
default:
463
return 0;
464
}
465
466
Register Imm = createResultReg(&WebAssembly::I32RegClass);
467
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
468
TII.get(WebAssembly::CONST_I32), Imm)
469
.addImm(~(~uint64_t(0) << MVT(From).getSizeInBits()));
470
471
Register Result = createResultReg(&WebAssembly::I32RegClass);
472
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
473
TII.get(WebAssembly::AND_I32), Result)
474
.addReg(Reg)
475
.addReg(Imm);
476
477
return Result;
478
}
479
480
unsigned WebAssemblyFastISel::signExtendToI32(unsigned Reg, const Value *V,
481
MVT::SimpleValueType From) {
482
if (Reg == 0)
483
return 0;
484
485
switch (From) {
486
case MVT::i1:
487
case MVT::i8:
488
case MVT::i16:
489
break;
490
case MVT::i32:
491
return copyValue(Reg);
492
default:
493
return 0;
494
}
495
496
Register Imm = createResultReg(&WebAssembly::I32RegClass);
497
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
498
TII.get(WebAssembly::CONST_I32), Imm)
499
.addImm(32 - MVT(From).getSizeInBits());
500
501
Register Left = createResultReg(&WebAssembly::I32RegClass);
502
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
503
TII.get(WebAssembly::SHL_I32), Left)
504
.addReg(Reg)
505
.addReg(Imm);
506
507
Register Right = createResultReg(&WebAssembly::I32RegClass);
508
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
509
TII.get(WebAssembly::SHR_S_I32), Right)
510
.addReg(Left)
511
.addReg(Imm);
512
513
return Right;
514
}
515
516
unsigned WebAssemblyFastISel::zeroExtend(unsigned Reg, const Value *V,
517
MVT::SimpleValueType From,
518
MVT::SimpleValueType To) {
519
if (To == MVT::i64) {
520
if (From == MVT::i64)
521
return copyValue(Reg);
522
523
Reg = zeroExtendToI32(Reg, V, From);
524
525
Register Result = createResultReg(&WebAssembly::I64RegClass);
526
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
527
TII.get(WebAssembly::I64_EXTEND_U_I32), Result)
528
.addReg(Reg);
529
return Result;
530
}
531
532
if (To == MVT::i32)
533
return zeroExtendToI32(Reg, V, From);
534
535
return 0;
536
}
537
538
unsigned WebAssemblyFastISel::signExtend(unsigned Reg, const Value *V,
539
MVT::SimpleValueType From,
540
MVT::SimpleValueType To) {
541
if (To == MVT::i64) {
542
if (From == MVT::i64)
543
return copyValue(Reg);
544
545
Reg = signExtendToI32(Reg, V, From);
546
547
Register Result = createResultReg(&WebAssembly::I64RegClass);
548
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
549
TII.get(WebAssembly::I64_EXTEND_S_I32), Result)
550
.addReg(Reg);
551
return Result;
552
}
553
554
if (To == MVT::i32)
555
return signExtendToI32(Reg, V, From);
556
557
return 0;
558
}
559
560
unsigned WebAssemblyFastISel::getRegForUnsignedValue(const Value *V) {
561
MVT::SimpleValueType From = getSimpleType(V->getType());
562
MVT::SimpleValueType To = getLegalType(From);
563
Register VReg = getRegForValue(V);
564
if (VReg == 0)
565
return 0;
566
if (From == To)
567
return VReg;
568
return zeroExtend(VReg, V, From, To);
569
}
570
571
unsigned WebAssemblyFastISel::getRegForSignedValue(const Value *V) {
572
MVT::SimpleValueType From = getSimpleType(V->getType());
573
MVT::SimpleValueType To = getLegalType(From);
574
Register VReg = getRegForValue(V);
575
if (VReg == 0)
576
return 0;
577
if (From == To)
578
return VReg;
579
return signExtend(VReg, V, From, To);
580
}
581
582
unsigned WebAssemblyFastISel::getRegForPromotedValue(const Value *V,
583
bool IsSigned) {
584
return IsSigned ? getRegForSignedValue(V) : getRegForUnsignedValue(V);
585
}
586
587
unsigned WebAssemblyFastISel::notValue(unsigned Reg) {
588
assert(MRI.getRegClass(Reg) == &WebAssembly::I32RegClass);
589
590
Register NotReg = createResultReg(&WebAssembly::I32RegClass);
591
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
592
TII.get(WebAssembly::EQZ_I32), NotReg)
593
.addReg(Reg);
594
return NotReg;
595
}
596
597
unsigned WebAssemblyFastISel::copyValue(unsigned Reg) {
598
Register ResultReg = createResultReg(MRI.getRegClass(Reg));
599
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(WebAssembly::COPY),
600
ResultReg)
601
.addReg(Reg);
602
return ResultReg;
603
}
604
605
unsigned WebAssemblyFastISel::fastMaterializeAlloca(const AllocaInst *AI) {
606
DenseMap<const AllocaInst *, int>::iterator SI =
607
FuncInfo.StaticAllocaMap.find(AI);
608
609
if (SI != FuncInfo.StaticAllocaMap.end()) {
610
Register ResultReg =
611
createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
612
: &WebAssembly::I32RegClass);
613
unsigned Opc =
614
Subtarget->hasAddr64() ? WebAssembly::COPY_I64 : WebAssembly::COPY_I32;
615
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
616
.addFrameIndex(SI->second);
617
return ResultReg;
618
}
619
620
return 0;
621
}
622
623
unsigned WebAssemblyFastISel::fastMaterializeConstant(const Constant *C) {
624
if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) {
625
if (TLI.isPositionIndependent())
626
return 0;
627
if (GV->isThreadLocal())
628
return 0;
629
Register ResultReg =
630
createResultReg(Subtarget->hasAddr64() ? &WebAssembly::I64RegClass
631
: &WebAssembly::I32RegClass);
632
unsigned Opc = Subtarget->hasAddr64() ? WebAssembly::CONST_I64
633
: WebAssembly::CONST_I32;
634
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
635
.addGlobalAddress(GV);
636
return ResultReg;
637
}
638
639
// Let target-independent code handle it.
640
return 0;
641
}
642
643
bool WebAssemblyFastISel::fastLowerArguments() {
644
if (!FuncInfo.CanLowerReturn)
645
return false;
646
647
const Function *F = FuncInfo.Fn;
648
if (F->isVarArg())
649
return false;
650
651
if (FuncInfo.Fn->getCallingConv() == CallingConv::Swift)
652
return false;
653
654
unsigned I = 0;
655
for (auto const &Arg : F->args()) {
656
const AttributeList &Attrs = F->getAttributes();
657
if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
658
Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
659
Attrs.hasParamAttr(I, Attribute::SwiftError) ||
660
Attrs.hasParamAttr(I, Attribute::InAlloca) ||
661
Attrs.hasParamAttr(I, Attribute::Nest))
662
return false;
663
664
Type *ArgTy = Arg.getType();
665
if (ArgTy->isStructTy() || ArgTy->isArrayTy())
666
return false;
667
if (!Subtarget->hasSIMD128() && ArgTy->isVectorTy())
668
return false;
669
670
unsigned Opc;
671
const TargetRegisterClass *RC;
672
switch (getSimpleType(ArgTy)) {
673
case MVT::i1:
674
case MVT::i8:
675
case MVT::i16:
676
case MVT::i32:
677
Opc = WebAssembly::ARGUMENT_i32;
678
RC = &WebAssembly::I32RegClass;
679
break;
680
case MVT::i64:
681
Opc = WebAssembly::ARGUMENT_i64;
682
RC = &WebAssembly::I64RegClass;
683
break;
684
case MVT::f32:
685
Opc = WebAssembly::ARGUMENT_f32;
686
RC = &WebAssembly::F32RegClass;
687
break;
688
case MVT::f64:
689
Opc = WebAssembly::ARGUMENT_f64;
690
RC = &WebAssembly::F64RegClass;
691
break;
692
case MVT::v16i8:
693
Opc = WebAssembly::ARGUMENT_v16i8;
694
RC = &WebAssembly::V128RegClass;
695
break;
696
case MVT::v8i16:
697
Opc = WebAssembly::ARGUMENT_v8i16;
698
RC = &WebAssembly::V128RegClass;
699
break;
700
case MVT::v4i32:
701
Opc = WebAssembly::ARGUMENT_v4i32;
702
RC = &WebAssembly::V128RegClass;
703
break;
704
case MVT::v2i64:
705
Opc = WebAssembly::ARGUMENT_v2i64;
706
RC = &WebAssembly::V128RegClass;
707
break;
708
case MVT::v4f32:
709
Opc = WebAssembly::ARGUMENT_v4f32;
710
RC = &WebAssembly::V128RegClass;
711
break;
712
case MVT::v2f64:
713
Opc = WebAssembly::ARGUMENT_v2f64;
714
RC = &WebAssembly::V128RegClass;
715
break;
716
case MVT::funcref:
717
Opc = WebAssembly::ARGUMENT_funcref;
718
RC = &WebAssembly::FUNCREFRegClass;
719
break;
720
case MVT::externref:
721
Opc = WebAssembly::ARGUMENT_externref;
722
RC = &WebAssembly::EXTERNREFRegClass;
723
break;
724
case MVT::exnref:
725
Opc = WebAssembly::ARGUMENT_exnref;
726
RC = &WebAssembly::EXNREFRegClass;
727
break;
728
default:
729
return false;
730
}
731
Register ResultReg = createResultReg(RC);
732
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
733
.addImm(I);
734
updateValueMap(&Arg, ResultReg);
735
736
++I;
737
}
738
739
MRI.addLiveIn(WebAssembly::ARGUMENTS);
740
741
auto *MFI = MF->getInfo<WebAssemblyFunctionInfo>();
742
for (auto const &Arg : F->args()) {
743
MVT::SimpleValueType ArgTy = getLegalType(getSimpleType(Arg.getType()));
744
if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
745
MFI->clearParamsAndResults();
746
return false;
747
}
748
MFI->addParam(ArgTy);
749
}
750
751
if (!F->getReturnType()->isVoidTy()) {
752
MVT::SimpleValueType RetTy =
753
getLegalType(getSimpleType(F->getReturnType()));
754
if (RetTy == MVT::INVALID_SIMPLE_VALUE_TYPE) {
755
MFI->clearParamsAndResults();
756
return false;
757
}
758
MFI->addResult(RetTy);
759
}
760
761
return true;
762
}
763
764
bool WebAssemblyFastISel::selectCall(const Instruction *I) {
765
const auto *Call = cast<CallInst>(I);
766
767
// TODO: Support tail calls in FastISel
768
if (Call->isMustTailCall() || Call->isInlineAsm() ||
769
Call->getFunctionType()->isVarArg())
770
return false;
771
772
Function *Func = Call->getCalledFunction();
773
if (Func && Func->isIntrinsic())
774
return false;
775
776
if (Call->getCallingConv() == CallingConv::Swift)
777
return false;
778
779
bool IsDirect = Func != nullptr;
780
if (!IsDirect && isa<ConstantExpr>(Call->getCalledOperand()))
781
return false;
782
783
FunctionType *FuncTy = Call->getFunctionType();
784
unsigned Opc = IsDirect ? WebAssembly::CALL : WebAssembly::CALL_INDIRECT;
785
bool IsVoid = FuncTy->getReturnType()->isVoidTy();
786
unsigned ResultReg;
787
if (!IsVoid) {
788
if (!Subtarget->hasSIMD128() && Call->getType()->isVectorTy())
789
return false;
790
791
MVT::SimpleValueType RetTy = getSimpleType(Call->getType());
792
switch (RetTy) {
793
case MVT::i1:
794
case MVT::i8:
795
case MVT::i16:
796
case MVT::i32:
797
ResultReg = createResultReg(&WebAssembly::I32RegClass);
798
break;
799
case MVT::i64:
800
ResultReg = createResultReg(&WebAssembly::I64RegClass);
801
break;
802
case MVT::f32:
803
ResultReg = createResultReg(&WebAssembly::F32RegClass);
804
break;
805
case MVT::f64:
806
ResultReg = createResultReg(&WebAssembly::F64RegClass);
807
break;
808
case MVT::v16i8:
809
ResultReg = createResultReg(&WebAssembly::V128RegClass);
810
break;
811
case MVT::v8i16:
812
ResultReg = createResultReg(&WebAssembly::V128RegClass);
813
break;
814
case MVT::v4i32:
815
ResultReg = createResultReg(&WebAssembly::V128RegClass);
816
break;
817
case MVT::v2i64:
818
ResultReg = createResultReg(&WebAssembly::V128RegClass);
819
break;
820
case MVT::v4f32:
821
ResultReg = createResultReg(&WebAssembly::V128RegClass);
822
break;
823
case MVT::v2f64:
824
ResultReg = createResultReg(&WebAssembly::V128RegClass);
825
break;
826
case MVT::funcref:
827
ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
828
break;
829
case MVT::externref:
830
ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
831
break;
832
case MVT::exnref:
833
ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
834
break;
835
default:
836
return false;
837
}
838
}
839
840
SmallVector<unsigned, 8> Args;
841
for (unsigned I = 0, E = Call->arg_size(); I < E; ++I) {
842
Value *V = Call->getArgOperand(I);
843
MVT::SimpleValueType ArgTy = getSimpleType(V->getType());
844
if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE)
845
return false;
846
847
const AttributeList &Attrs = Call->getAttributes();
848
if (Attrs.hasParamAttr(I, Attribute::ByVal) ||
849
Attrs.hasParamAttr(I, Attribute::SwiftSelf) ||
850
Attrs.hasParamAttr(I, Attribute::SwiftError) ||
851
Attrs.hasParamAttr(I, Attribute::InAlloca) ||
852
Attrs.hasParamAttr(I, Attribute::Nest))
853
return false;
854
855
unsigned Reg;
856
857
if (Call->paramHasAttr(I, Attribute::SExt))
858
Reg = getRegForSignedValue(V);
859
else if (Call->paramHasAttr(I, Attribute::ZExt))
860
Reg = getRegForUnsignedValue(V);
861
else
862
Reg = getRegForValue(V);
863
864
if (Reg == 0)
865
return false;
866
867
Args.push_back(Reg);
868
}
869
870
unsigned CalleeReg = 0;
871
if (!IsDirect) {
872
CalleeReg = getRegForValue(Call->getCalledOperand());
873
if (!CalleeReg)
874
return false;
875
}
876
877
auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
878
879
if (!IsVoid)
880
MIB.addReg(ResultReg, RegState::Define);
881
882
if (IsDirect) {
883
MIB.addGlobalAddress(Func);
884
} else {
885
// Placeholder for the type index.
886
MIB.addImm(0);
887
// The table into which this call_indirect indexes.
888
MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol(
889
MF->getContext(), Subtarget);
890
if (Subtarget->hasReferenceTypes()) {
891
MIB.addSym(Table);
892
} else {
893
// Otherwise for the MVP there is at most one table whose number is 0, but
894
// we can't write a table symbol or issue relocations. Instead we just
895
// ensure the table is live.
896
Table->setNoStrip();
897
MIB.addImm(0);
898
}
899
}
900
901
for (unsigned ArgReg : Args)
902
MIB.addReg(ArgReg);
903
904
if (!IsDirect)
905
MIB.addReg(CalleeReg);
906
907
if (!IsVoid)
908
updateValueMap(Call, ResultReg);
909
return true;
910
}
911
912
bool WebAssemblyFastISel::selectSelect(const Instruction *I) {
913
const auto *Select = cast<SelectInst>(I);
914
915
bool Not;
916
unsigned CondReg =
917
getRegForI1Value(Select->getCondition(), I->getParent(), Not);
918
if (CondReg == 0)
919
return false;
920
921
Register TrueReg = getRegForValue(Select->getTrueValue());
922
if (TrueReg == 0)
923
return false;
924
925
Register FalseReg = getRegForValue(Select->getFalseValue());
926
if (FalseReg == 0)
927
return false;
928
929
if (Not)
930
std::swap(TrueReg, FalseReg);
931
932
unsigned Opc;
933
const TargetRegisterClass *RC;
934
switch (getSimpleType(Select->getType())) {
935
case MVT::i1:
936
case MVT::i8:
937
case MVT::i16:
938
case MVT::i32:
939
Opc = WebAssembly::SELECT_I32;
940
RC = &WebAssembly::I32RegClass;
941
break;
942
case MVT::i64:
943
Opc = WebAssembly::SELECT_I64;
944
RC = &WebAssembly::I64RegClass;
945
break;
946
case MVT::f32:
947
Opc = WebAssembly::SELECT_F32;
948
RC = &WebAssembly::F32RegClass;
949
break;
950
case MVT::f64:
951
Opc = WebAssembly::SELECT_F64;
952
RC = &WebAssembly::F64RegClass;
953
break;
954
case MVT::funcref:
955
Opc = WebAssembly::SELECT_FUNCREF;
956
RC = &WebAssembly::FUNCREFRegClass;
957
break;
958
case MVT::externref:
959
Opc = WebAssembly::SELECT_EXTERNREF;
960
RC = &WebAssembly::EXTERNREFRegClass;
961
break;
962
case MVT::exnref:
963
Opc = WebAssembly::SELECT_EXNREF;
964
RC = &WebAssembly::EXNREFRegClass;
965
break;
966
default:
967
return false;
968
}
969
970
Register ResultReg = createResultReg(RC);
971
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
972
.addReg(TrueReg)
973
.addReg(FalseReg)
974
.addReg(CondReg);
975
976
updateValueMap(Select, ResultReg);
977
return true;
978
}
979
980
bool WebAssemblyFastISel::selectTrunc(const Instruction *I) {
981
const auto *Trunc = cast<TruncInst>(I);
982
983
Register Reg = getRegForValue(Trunc->getOperand(0));
984
if (Reg == 0)
985
return false;
986
987
if (Trunc->getOperand(0)->getType()->isIntegerTy(64)) {
988
Register Result = createResultReg(&WebAssembly::I32RegClass);
989
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
990
TII.get(WebAssembly::I32_WRAP_I64), Result)
991
.addReg(Reg);
992
Reg = Result;
993
}
994
995
updateValueMap(Trunc, Reg);
996
return true;
997
}
998
999
bool WebAssemblyFastISel::selectZExt(const Instruction *I) {
1000
const auto *ZExt = cast<ZExtInst>(I);
1001
1002
const Value *Op = ZExt->getOperand(0);
1003
MVT::SimpleValueType From = getSimpleType(Op->getType());
1004
MVT::SimpleValueType To = getLegalType(getSimpleType(ZExt->getType()));
1005
Register In = getRegForValue(Op);
1006
if (In == 0)
1007
return false;
1008
unsigned Reg = zeroExtend(In, Op, From, To);
1009
if (Reg == 0)
1010
return false;
1011
1012
updateValueMap(ZExt, Reg);
1013
return true;
1014
}
1015
1016
bool WebAssemblyFastISel::selectSExt(const Instruction *I) {
1017
const auto *SExt = cast<SExtInst>(I);
1018
1019
const Value *Op = SExt->getOperand(0);
1020
MVT::SimpleValueType From = getSimpleType(Op->getType());
1021
MVT::SimpleValueType To = getLegalType(getSimpleType(SExt->getType()));
1022
Register In = getRegForValue(Op);
1023
if (In == 0)
1024
return false;
1025
unsigned Reg = signExtend(In, Op, From, To);
1026
if (Reg == 0)
1027
return false;
1028
1029
updateValueMap(SExt, Reg);
1030
return true;
1031
}
1032
1033
bool WebAssemblyFastISel::selectICmp(const Instruction *I) {
1034
const auto *ICmp = cast<ICmpInst>(I);
1035
1036
bool I32 = getSimpleType(ICmp->getOperand(0)->getType()) != MVT::i64;
1037
unsigned Opc;
1038
bool IsSigned = false;
1039
switch (ICmp->getPredicate()) {
1040
case ICmpInst::ICMP_EQ:
1041
Opc = I32 ? WebAssembly::EQ_I32 : WebAssembly::EQ_I64;
1042
break;
1043
case ICmpInst::ICMP_NE:
1044
Opc = I32 ? WebAssembly::NE_I32 : WebAssembly::NE_I64;
1045
break;
1046
case ICmpInst::ICMP_UGT:
1047
Opc = I32 ? WebAssembly::GT_U_I32 : WebAssembly::GT_U_I64;
1048
break;
1049
case ICmpInst::ICMP_UGE:
1050
Opc = I32 ? WebAssembly::GE_U_I32 : WebAssembly::GE_U_I64;
1051
break;
1052
case ICmpInst::ICMP_ULT:
1053
Opc = I32 ? WebAssembly::LT_U_I32 : WebAssembly::LT_U_I64;
1054
break;
1055
case ICmpInst::ICMP_ULE:
1056
Opc = I32 ? WebAssembly::LE_U_I32 : WebAssembly::LE_U_I64;
1057
break;
1058
case ICmpInst::ICMP_SGT:
1059
Opc = I32 ? WebAssembly::GT_S_I32 : WebAssembly::GT_S_I64;
1060
IsSigned = true;
1061
break;
1062
case ICmpInst::ICMP_SGE:
1063
Opc = I32 ? WebAssembly::GE_S_I32 : WebAssembly::GE_S_I64;
1064
IsSigned = true;
1065
break;
1066
case ICmpInst::ICMP_SLT:
1067
Opc = I32 ? WebAssembly::LT_S_I32 : WebAssembly::LT_S_I64;
1068
IsSigned = true;
1069
break;
1070
case ICmpInst::ICMP_SLE:
1071
Opc = I32 ? WebAssembly::LE_S_I32 : WebAssembly::LE_S_I64;
1072
IsSigned = true;
1073
break;
1074
default:
1075
return false;
1076
}
1077
1078
unsigned LHS = getRegForPromotedValue(ICmp->getOperand(0), IsSigned);
1079
if (LHS == 0)
1080
return false;
1081
1082
unsigned RHS = getRegForPromotedValue(ICmp->getOperand(1), IsSigned);
1083
if (RHS == 0)
1084
return false;
1085
1086
Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1087
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1088
.addReg(LHS)
1089
.addReg(RHS);
1090
updateValueMap(ICmp, ResultReg);
1091
return true;
1092
}
1093
1094
bool WebAssemblyFastISel::selectFCmp(const Instruction *I) {
1095
const auto *FCmp = cast<FCmpInst>(I);
1096
1097
Register LHS = getRegForValue(FCmp->getOperand(0));
1098
if (LHS == 0)
1099
return false;
1100
1101
Register RHS = getRegForValue(FCmp->getOperand(1));
1102
if (RHS == 0)
1103
return false;
1104
1105
bool F32 = getSimpleType(FCmp->getOperand(0)->getType()) != MVT::f64;
1106
unsigned Opc;
1107
bool Not = false;
1108
switch (FCmp->getPredicate()) {
1109
case FCmpInst::FCMP_OEQ:
1110
Opc = F32 ? WebAssembly::EQ_F32 : WebAssembly::EQ_F64;
1111
break;
1112
case FCmpInst::FCMP_UNE:
1113
Opc = F32 ? WebAssembly::NE_F32 : WebAssembly::NE_F64;
1114
break;
1115
case FCmpInst::FCMP_OGT:
1116
Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1117
break;
1118
case FCmpInst::FCMP_OGE:
1119
Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1120
break;
1121
case FCmpInst::FCMP_OLT:
1122
Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1123
break;
1124
case FCmpInst::FCMP_OLE:
1125
Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1126
break;
1127
case FCmpInst::FCMP_UGT:
1128
Opc = F32 ? WebAssembly::LE_F32 : WebAssembly::LE_F64;
1129
Not = true;
1130
break;
1131
case FCmpInst::FCMP_UGE:
1132
Opc = F32 ? WebAssembly::LT_F32 : WebAssembly::LT_F64;
1133
Not = true;
1134
break;
1135
case FCmpInst::FCMP_ULT:
1136
Opc = F32 ? WebAssembly::GE_F32 : WebAssembly::GE_F64;
1137
Not = true;
1138
break;
1139
case FCmpInst::FCMP_ULE:
1140
Opc = F32 ? WebAssembly::GT_F32 : WebAssembly::GT_F64;
1141
Not = true;
1142
break;
1143
default:
1144
return false;
1145
}
1146
1147
Register ResultReg = createResultReg(&WebAssembly::I32RegClass);
1148
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg)
1149
.addReg(LHS)
1150
.addReg(RHS);
1151
1152
if (Not)
1153
ResultReg = notValue(ResultReg);
1154
1155
updateValueMap(FCmp, ResultReg);
1156
return true;
1157
}
1158
1159
bool WebAssemblyFastISel::selectBitCast(const Instruction *I) {
1160
// Target-independent code can handle this, except it doesn't set the dead
1161
// flag on the ARGUMENTS clobber, so we have to do that manually in order
1162
// to satisfy code that expects this of isBitcast() instructions.
1163
EVT VT = TLI.getValueType(DL, I->getOperand(0)->getType());
1164
EVT RetVT = TLI.getValueType(DL, I->getType());
1165
if (!VT.isSimple() || !RetVT.isSimple())
1166
return false;
1167
1168
Register In = getRegForValue(I->getOperand(0));
1169
if (In == 0)
1170
return false;
1171
1172
if (VT == RetVT) {
1173
// No-op bitcast.
1174
updateValueMap(I, In);
1175
return true;
1176
}
1177
1178
Register Reg = fastEmit_ISD_BITCAST_r(VT.getSimpleVT(), RetVT.getSimpleVT(),
1179
In);
1180
if (!Reg)
1181
return false;
1182
MachineBasicBlock::iterator Iter = FuncInfo.InsertPt;
1183
--Iter;
1184
assert(Iter->isBitcast());
1185
Iter->setPhysRegsDeadExcept(ArrayRef<Register>(), TRI);
1186
updateValueMap(I, Reg);
1187
return true;
1188
}
1189
1190
bool WebAssemblyFastISel::selectLoad(const Instruction *I) {
1191
const auto *Load = cast<LoadInst>(I);
1192
if (Load->isAtomic())
1193
return false;
1194
if (!WebAssembly::isDefaultAddressSpace(Load->getPointerAddressSpace()))
1195
return false;
1196
if (!Subtarget->hasSIMD128() && Load->getType()->isVectorTy())
1197
return false;
1198
1199
Address Addr;
1200
if (!computeAddress(Load->getPointerOperand(), Addr))
1201
return false;
1202
1203
// TODO: Fold a following sign-/zero-extend into the load instruction.
1204
1205
unsigned Opc;
1206
const TargetRegisterClass *RC;
1207
bool A64 = Subtarget->hasAddr64();
1208
switch (getSimpleType(Load->getType())) {
1209
case MVT::i1:
1210
case MVT::i8:
1211
Opc = A64 ? WebAssembly::LOAD8_U_I32_A64 : WebAssembly::LOAD8_U_I32_A32;
1212
RC = &WebAssembly::I32RegClass;
1213
break;
1214
case MVT::i16:
1215
Opc = A64 ? WebAssembly::LOAD16_U_I32_A64 : WebAssembly::LOAD16_U_I32_A32;
1216
RC = &WebAssembly::I32RegClass;
1217
break;
1218
case MVT::i32:
1219
Opc = A64 ? WebAssembly::LOAD_I32_A64 : WebAssembly::LOAD_I32_A32;
1220
RC = &WebAssembly::I32RegClass;
1221
break;
1222
case MVT::i64:
1223
Opc = A64 ? WebAssembly::LOAD_I64_A64 : WebAssembly::LOAD_I64_A32;
1224
RC = &WebAssembly::I64RegClass;
1225
break;
1226
case MVT::f32:
1227
Opc = A64 ? WebAssembly::LOAD_F32_A64 : WebAssembly::LOAD_F32_A32;
1228
RC = &WebAssembly::F32RegClass;
1229
break;
1230
case MVT::f64:
1231
Opc = A64 ? WebAssembly::LOAD_F64_A64 : WebAssembly::LOAD_F64_A32;
1232
RC = &WebAssembly::F64RegClass;
1233
break;
1234
default:
1235
return false;
1236
}
1237
1238
materializeLoadStoreOperands(Addr);
1239
1240
Register ResultReg = createResultReg(RC);
1241
auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc),
1242
ResultReg);
1243
1244
addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Load));
1245
1246
updateValueMap(Load, ResultReg);
1247
return true;
1248
}
1249
1250
bool WebAssemblyFastISel::selectStore(const Instruction *I) {
1251
const auto *Store = cast<StoreInst>(I);
1252
if (Store->isAtomic())
1253
return false;
1254
if (!WebAssembly::isDefaultAddressSpace(Store->getPointerAddressSpace()))
1255
return false;
1256
if (!Subtarget->hasSIMD128() &&
1257
Store->getValueOperand()->getType()->isVectorTy())
1258
return false;
1259
1260
Address Addr;
1261
if (!computeAddress(Store->getPointerOperand(), Addr))
1262
return false;
1263
1264
unsigned Opc;
1265
bool VTIsi1 = false;
1266
bool A64 = Subtarget->hasAddr64();
1267
switch (getSimpleType(Store->getValueOperand()->getType())) {
1268
case MVT::i1:
1269
VTIsi1 = true;
1270
[[fallthrough]];
1271
case MVT::i8:
1272
Opc = A64 ? WebAssembly::STORE8_I32_A64 : WebAssembly::STORE8_I32_A32;
1273
break;
1274
case MVT::i16:
1275
Opc = A64 ? WebAssembly::STORE16_I32_A64 : WebAssembly::STORE16_I32_A32;
1276
break;
1277
case MVT::i32:
1278
Opc = A64 ? WebAssembly::STORE_I32_A64 : WebAssembly::STORE_I32_A32;
1279
break;
1280
case MVT::i64:
1281
Opc = A64 ? WebAssembly::STORE_I64_A64 : WebAssembly::STORE_I64_A32;
1282
break;
1283
case MVT::f32:
1284
Opc = A64 ? WebAssembly::STORE_F32_A64 : WebAssembly::STORE_F32_A32;
1285
break;
1286
case MVT::f64:
1287
Opc = A64 ? WebAssembly::STORE_F64_A64 : WebAssembly::STORE_F64_A32;
1288
break;
1289
default:
1290
return false;
1291
}
1292
1293
materializeLoadStoreOperands(Addr);
1294
1295
Register ValueReg = getRegForValue(Store->getValueOperand());
1296
if (ValueReg == 0)
1297
return false;
1298
if (VTIsi1)
1299
ValueReg = maskI1Value(ValueReg, Store->getValueOperand());
1300
1301
auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc));
1302
1303
addLoadStoreOperands(Addr, MIB, createMachineMemOperandFor(Store));
1304
1305
MIB.addReg(ValueReg);
1306
return true;
1307
}
1308
1309
bool WebAssemblyFastISel::selectBr(const Instruction *I) {
1310
const auto *Br = cast<BranchInst>(I);
1311
if (Br->isUnconditional()) {
1312
MachineBasicBlock *MSucc = FuncInfo.MBBMap[Br->getSuccessor(0)];
1313
fastEmitBranch(MSucc, Br->getDebugLoc());
1314
return true;
1315
}
1316
1317
MachineBasicBlock *TBB = FuncInfo.MBBMap[Br->getSuccessor(0)];
1318
MachineBasicBlock *FBB = FuncInfo.MBBMap[Br->getSuccessor(1)];
1319
1320
bool Not;
1321
unsigned CondReg = getRegForI1Value(Br->getCondition(), Br->getParent(), Not);
1322
if (CondReg == 0)
1323
return false;
1324
1325
unsigned Opc = WebAssembly::BR_IF;
1326
if (Not)
1327
Opc = WebAssembly::BR_UNLESS;
1328
1329
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc))
1330
.addMBB(TBB)
1331
.addReg(CondReg);
1332
1333
finishCondBranch(Br->getParent(), TBB, FBB);
1334
return true;
1335
}
1336
1337
bool WebAssemblyFastISel::selectRet(const Instruction *I) {
1338
if (!FuncInfo.CanLowerReturn)
1339
return false;
1340
1341
const auto *Ret = cast<ReturnInst>(I);
1342
1343
if (Ret->getNumOperands() == 0) {
1344
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1345
TII.get(WebAssembly::RETURN));
1346
return true;
1347
}
1348
1349
// TODO: support multiple return in FastISel
1350
if (Ret->getNumOperands() > 1)
1351
return false;
1352
1353
Value *RV = Ret->getOperand(0);
1354
if (!Subtarget->hasSIMD128() && RV->getType()->isVectorTy())
1355
return false;
1356
1357
switch (getSimpleType(RV->getType())) {
1358
case MVT::i1:
1359
case MVT::i8:
1360
case MVT::i16:
1361
case MVT::i32:
1362
case MVT::i64:
1363
case MVT::f32:
1364
case MVT::f64:
1365
case MVT::v16i8:
1366
case MVT::v8i16:
1367
case MVT::v4i32:
1368
case MVT::v2i64:
1369
case MVT::v4f32:
1370
case MVT::v2f64:
1371
case MVT::funcref:
1372
case MVT::externref:
1373
case MVT::exnref:
1374
break;
1375
default:
1376
return false;
1377
}
1378
1379
unsigned Reg;
1380
if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::SExt))
1381
Reg = getRegForSignedValue(RV);
1382
else if (FuncInfo.Fn->getAttributes().hasRetAttr(Attribute::ZExt))
1383
Reg = getRegForUnsignedValue(RV);
1384
else
1385
Reg = getRegForValue(RV);
1386
1387
if (Reg == 0)
1388
return false;
1389
1390
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1391
TII.get(WebAssembly::RETURN))
1392
.addReg(Reg);
1393
return true;
1394
}
1395
1396
bool WebAssemblyFastISel::selectUnreachable(const Instruction *I) {
1397
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD,
1398
TII.get(WebAssembly::UNREACHABLE));
1399
return true;
1400
}
1401
1402
bool WebAssemblyFastISel::fastSelectInstruction(const Instruction *I) {
1403
switch (I->getOpcode()) {
1404
case Instruction::Call:
1405
if (selectCall(I))
1406
return true;
1407
break;
1408
case Instruction::Select:
1409
return selectSelect(I);
1410
case Instruction::Trunc:
1411
return selectTrunc(I);
1412
case Instruction::ZExt:
1413
return selectZExt(I);
1414
case Instruction::SExt:
1415
return selectSExt(I);
1416
case Instruction::ICmp:
1417
return selectICmp(I);
1418
case Instruction::FCmp:
1419
return selectFCmp(I);
1420
case Instruction::BitCast:
1421
return selectBitCast(I);
1422
case Instruction::Load:
1423
return selectLoad(I);
1424
case Instruction::Store:
1425
return selectStore(I);
1426
case Instruction::Br:
1427
return selectBr(I);
1428
case Instruction::Ret:
1429
return selectRet(I);
1430
case Instruction::Unreachable:
1431
return selectUnreachable(I);
1432
default:
1433
break;
1434
}
1435
1436
// Fall back to target-independent instruction selection.
1437
return selectOperator(I, I->getOpcode());
1438
}
1439
1440
FastISel *WebAssembly::createFastISel(FunctionLoweringInfo &FuncInfo,
1441
const TargetLibraryInfo *LibInfo) {
1442
return new WebAssemblyFastISel(FuncInfo, LibInfo);
1443
}
1444
1445