LLVM: lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

24#include "llvm/IR/IntrinsicsWebAssembly.h"

29

30using namespace llvm;

31

32#define DEBUG_TYPE "wasm-isel"

33#define PASS_NAME "WebAssembly Instruction Selection"

34

35

36

37

38

39namespace {

40class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {

41

42

44

45public:

46 WebAssemblyDAGToDAGISel() = delete;

47

51

53 LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"

54 "********** Function: "

56

58

60 }

61

62 void PreprocessISelDAG() override;

63

65

66 bool SelectInlineAsmMemoryOperand(const SDValue &Op,

68 std::vector &OutOps) override;

69

72

73

74#include "WebAssemblyGenDAGISel.inc"

75

76private:

77

78

79 bool SelectAddrOperands(MVT AddrType, unsigned ConstOpc, SDValue Op,

83};

84

86public:

87 static char ID;

91 ID, std::make_unique(TM, OptLevel)) {}

92};

93}

94

95char WebAssemblyDAGToDAGISelLegacy::ID;

96

98 false)

99

100void WebAssemblyDAGToDAGISel::PreprocessISelDAG() {

101

102

103

104

108

110}

111

118 ? MF.createExternalSymbolName("__cpp_exception")

119 : MF.createExternalSymbolName("__c_longjmp");

121}

122

126 auto toWasmValType = [](MVT VT) {

127 if (VT == MVT::i32) {

129 }

130 if (VT == MVT::i64) {

132 }

133 if (VT == MVT::f32) {

135 }

136 if (VT == MVT::f64) {

138 }

139 if (VT == MVT::externref) {

141 }

142 if (VT == MVT::funcref) {

144 }

145 if (VT == MVT::exnref) {

147 }

148 LLVM_DEBUG(errs() << "Unhandled type for llvm.wasm.ref.test.func: " << VT

149 << "\n");

150 llvm_unreachable("Unhandled type for llvm.wasm.ref.test.func");

151 };

152 auto NParams = Params.size();

153 auto NReturns = Returns.size();

154 auto BitWidth = (NParams + NReturns + 2) * 64;

156

157

158

159

160

161 Sig |= NReturns ^ 0x7ffffff;

162 for (auto &Return : Returns) {

163 auto V = toWasmValType(Return);

164 Sig <<= 64;

165 Sig |= (int64_t)V;

166 }

167 Sig <<= 64;

168 Sig |= NParams;

169 for (auto &Param : Params) {

170 auto V = toWasmValType(Param);

171 Sig <<= 64;

172 Sig |= (int64_t)V;

173 }

174 return Sig;

175}

176

177void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {

178

179 if (Node->isMachineOpcode()) {

181 Node->setNodeId(-1);

182 return;

183 }

184

185 MVT PtrVT = TLI->getPointerTy(CurDAG->getDataLayout());

186 auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64

187 : WebAssembly::GLOBAL_GET_I32;

188

189

190 SDLoc DL(Node);

191 MachineFunction &MF = CurDAG->getMachineFunction();

192 switch (Node->getOpcode()) {

193 case ISD::ATOMIC_FENCE: {

194 if (!MF.getSubtarget().hasAtomics())

195 break;

196

197 uint64_t SyncScopeID = Node->getConstantOperandVal(2);

198 MachineSDNode *Fence = nullptr;

199 switch (SyncScopeID) {

201

202

203

204 Fence = CurDAG->getMachineNode(WebAssembly::COMPILER_FENCE,

205 DL,

206 MVT::Other,

207 Node->getOperand(0)

208 );

209 break;

211

212

213 Fence = CurDAG->getMachineNode(

214 WebAssembly::ATOMIC_FENCE,

215 DL,

216 MVT::Other,

217 CurDAG->getTargetConstant(0, DL, MVT::i32),

218 Node->getOperand(0)

219 );

220 break;

221 default:

223 }

224

225 ReplaceNode(Node, Fence);

226 CurDAG->RemoveDeadNode(Node);

227 return;

228 }

229

231 unsigned IntNo = Node->getConstantOperandVal(0);

232 switch (IntNo) {

233 case Intrinsic::wasm_tls_size: {

234 MachineSDNode *TLSSize = CurDAG->getMachineNode(

235 GlobalGetIns, DL, PtrVT,

236 CurDAG->getTargetExternalSymbol("__tls_size", PtrVT));

237 ReplaceNode(Node, TLSSize);

238 return;

239 }

240

241 case Intrinsic::wasm_tls_align: {

242 MachineSDNode *TLSAlign = CurDAG->getMachineNode(

243 GlobalGetIns, DL, PtrVT,

244 CurDAG->getTargetExternalSymbol("__tls_align", PtrVT));

245 ReplaceNode(Node, TLSAlign);

246 return;

247 }

248 case Intrinsic::wasm_ref_test_func: {

249

250

251 MachineFunction &MF = CurDAG->getMachineFunction();

255 SDValue TableSym = CurDAG->getMCSymbol(Table, PtrVT);

258

259

260 FuncPtr = SDValue(CurDAG->getMachineNode(WebAssembly::I32_WRAP_I64, DL,

261 MVT::i32, FuncPtr),

262 0);

263 }

265 SDValue(CurDAG->getMachineNode(WebAssembly::TABLE_GET_FUNCREF, DL,

266 MVT::funcref, TableSym, FuncPtr),

267 0);

268

269

270

271

274

275 bool IsParam = false;

276

277

278

279 for (unsigned I = 2, E = Node->getNumOperands(); I < E; ++I) {

280 MVT VT = Node->getOperand(I).getValueType().getSimpleVT();

281 if (VT == MVT::Untyped) {

282 IsParam = true;

283 continue;

284 }

285 if (IsParam) {

287 } else {

289 }

290 }

292

293 auto SigOp = CurDAG->getTargetConstant(

295 MachineSDNode *RefTestNode = CurDAG->getMachineNode(

296 WebAssembly::REF_TEST_FUNCREF, DL, MVT::i32, {SigOp, FuncRef});

297 ReplaceNode(Node, RefTestNode);

298 return;

299 }

300 }

301 break;

302 }

303

305 unsigned IntNo = Node->getConstantOperandVal(1);

306 const auto &TLI = CurDAG->getTargetLoweringInfo();

307 MVT PtrVT = TLI.getPointerTy(CurDAG->getDataLayout());

308 switch (IntNo) {

309 case Intrinsic::wasm_tls_base: {

310 MachineSDNode *TLSBase = CurDAG->getMachineNode(

311 GlobalGetIns, DL, PtrVT, MVT::Other,

312 CurDAG->getTargetExternalSymbol("__tls_base", PtrVT),

313 Node->getOperand(0));

314 ReplaceNode(Node, TLSBase);

315 return;

316 }

317

318 case Intrinsic::wasm_catch: {

319 int Tag = Node->getConstantOperandVal(2);

322 ? WebAssembly::CATCH_LEGACY

323 : WebAssembly::CATCH;

324 MachineSDNode *Catch =

325 CurDAG->getMachineNode(CatchOpcode, DL,

326 {

327 PtrVT,

328 MVT::Other

329 },

330 {

331 SymNode,

332 Node->getOperand(0)

333 });

334 ReplaceNode(Node, Catch);

335 return;

336 }

337 }

338 break;

339 }

340

342 unsigned IntNo = Node->getConstantOperandVal(1);

343 switch (IntNo) {

344 case Intrinsic::wasm_throw: {

345 int Tag = Node->getConstantOperandVal(2);

347 MachineSDNode *Throw =

348 CurDAG->getMachineNode(WebAssembly::THROW, DL,

349 MVT::Other,

350 {

351 SymNode,

352 Node->getOperand(3),

353 Node->getOperand(0)

354 });

355 ReplaceNode(Node, Throw);

356 return;

357 }

358 case Intrinsic::wasm_rethrow: {

359

360

361 MachineSDNode *Rethrow = CurDAG->getMachineNode(

362 WebAssembly::RETHROW, DL,

363 MVT::Other,

364 {

365 CurDAG->getConstant(0, DL, MVT::i32),

366 Node->getOperand(0)

367 });

368 ReplaceNode(Node, Rethrow);

369 return;

370 }

371 }

372 break;

373 }

374

377

378

379

380

382 for (size_t i = 1; i < Node->getNumOperands(); ++i) {

384

385

386

387

388

389

390 if (i == 1 && Op->getOpcode() == WebAssemblyISD::Wrapper) {

391 SDValue NewOp = Op->getOperand(0);

394 GlobalOp->getGlobal()->stripPointerCastsAndAliases()))

395 Op = NewOp;

397 Op = NewOp;

398 }

399 }

400 Ops.push_back(Op);

401 }

402

403

404 Ops.push_back(Node->getOperand(0));

405 MachineSDNode *CallParams =

406 CurDAG->getMachineNode(WebAssembly::CALL_PARAMS, DL, MVT::Glue, Ops);

407

409 ? WebAssembly::CALL_RESULTS

410 : WebAssembly::RET_CALL_RESULTS;

411

412 SDValue Link(CallParams, 0);

413 MachineSDNode *CallResults =

414 CurDAG->getMachineNode(Results, DL, Node->getVTList(), Link);

415 ReplaceNode(Node, CallResults);

416 return;

417 }

418

419 default:

420 break;

421 }

422

423

424 SelectCode(Node);

425}

426

427bool WebAssemblyDAGToDAGISel::SelectInlineAsmMemoryOperand(

429 std::vector &OutOps) {

430 switch (ConstraintID) {

431 case InlineAsm::ConstraintCode::m:

432

433

434 OutOps.push_back(Op);

435 return false;

436 default:

437 break;

438 }

439

440 return true;

441}

442

443bool WebAssemblyDAGToDAGISel::SelectAddrAddOperands(MVT OffsetType, SDValue N,

446 assert(N.getNumOperands() == 2 && "Attempting to fold in a non-binary op");

447

448

449

450

451 if (N.getOpcode() == ISD::ADD && N.getNode()->getFlags().hasNoUnsignedWrap())

452 return false;

453

454 for (size_t i = 0; i < 2; ++i) {

456 SDValue OtherOp = N.getOperand(i == 0 ? 1 : 0);

457

458

461 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), OffsetType);

462 Addr = OtherOp;

463 return true;

464 }

465

466

467 if (!TM.isPositionIndependent()) {

468 if (Op.getOpcode() == WebAssemblyISD::Wrapper)

469 Op = Op.getOperand(0);

470

472 Addr = OtherOp;

474 return true;

475 }

476 }

477 }

478 return false;

479}

480

481bool WebAssemblyDAGToDAGISel::SelectAddrOperands(MVT AddrType,

482 unsigned ConstOpc, SDValue N,

485 SDLoc DL(N);

486

487

488 if (!TM.isPositionIndependent()) {

490 if (Op.getOpcode() == WebAssemblyISD::Wrapper)

491 Op = Op.getOperand(0);

492

496 CurDAG->getMachineNode(ConstOpc, DL, AddrType,

497 CurDAG->getTargetConstant(0, DL, AddrType)),

498 0);

499 return true;

500 }

501 }

502

503

505 SelectAddrAddOperands(AddrType, N, Offset, Addr))

506 return true;

507

508

509

510 if (N.getOpcode() == ISD::OR) {

511 bool OrIsAdd;

513 OrIsAdd =

514 CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());

515 } else {

516 KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);

517 KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);

518 OrIsAdd = (~Known0.Zero & ~Known1.Zero) == 0;

519 }

520

521 if (OrIsAdd && SelectAddrAddOperands(AddrType, N, Offset, Addr))

522 return true;

523 }

524

525

527 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, AddrType);

529 CurDAG->getMachineNode(ConstOpc, DL, AddrType,

530 CurDAG->getTargetConstant(0, DL, AddrType)),

531 0);

532 return true;

533 }

534

535

536 Offset = CurDAG->getTargetConstant(0, DL, AddrType);

537 Addr = N;

538 return true;

539}

540

543 return SelectAddrOperands(MVT::i32, WebAssembly::CONST_I32, Op, Offset, Addr);

544}

545

548 return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64, Op, Offset, Addr);

549}

550

551

552

555 return new WebAssemblyDAGToDAGISelLegacy(TM, OptLevel);

556}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

AMDGPU Register Bank Select

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Function Alias Analysis Results

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]

#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)

static SDValue getTagSymNode(int Tag, SelectionDAG *DAG)

Definition WebAssemblyISelDAGToDAG.cpp:112

static APInt encodeFunctionSignature(SelectionDAG *DAG, SDLoc &DL, SmallVector< MVT, 4 > &Returns, SmallVector< MVT, 4 > &Params)

Definition WebAssemblyISelDAGToDAG.cpp:123

This file defines the interfaces that WebAssembly uses to lower LLVM code into a selection DAG.

This file provides WebAssembly-specific target descriptions.

This file declares the WebAssembly-specific subclass of TargetMachine.

This file contains the declaration of the WebAssembly-specific utility functions.

This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.

Class for arbitrary precision integers.

unsigned getPointerSizeInBits(unsigned AS=0) const

The size in bits of the pointer representation in a given address space.

FunctionPass class - This class is used to implement most global optimizations.

static MVT getIntegerVT(unsigned BitWidth)

The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted.

int getObjectIndexEnd() const

Return one past the maximum frame object index.

const TargetSubtargetInfo & getSubtarget() const

getSubtarget - Return the subtarget for which this machine code is being compiled.

StringRef getName() const

getName - Return the name of the corresponding LLVM function.

MCContext & getContext() const

const DataLayout & getDataLayout() const

Return the DataLayout attached to the Module associated to this MF.

Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...

Represents one node in the SelectionDAG.

Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.

SDNode * getNode() const

get the SDNode which holds the desired result

EVT getValueType() const

Return the ValueType of the referenced return value.

SelectionDAGISel - This is the common base class used for SelectionDAG-based pattern-matching instruc...

virtual void PreprocessISelDAG()

PreprocessISelDAG - This hook allows targets to hack on the graph before instruction selection starts...

virtual bool runOnMachineFunction(MachineFunction &mf)

This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...

const TargetLowering & getTargetLoweringInfo() const

const DataLayout & getDataLayout() const

MachineFunction & getMachineFunction() const

LLVM_ABI SDValue getTargetExternalSymbol(const char *Sym, EVT VT, unsigned TargetFlags=0)

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

static std::optional< unsigned > getLocalForStackObject(MachineFunction &MF, int FrameIndex)

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ ADD

Simple integer binary arithmetic operators.

@ INTRINSIC_VOID

OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...

@ TargetGlobalAddress

TargetGlobalAddress - Like GlobalAddress, but the DAG does no folding or anything else with this node...

@ INTRINSIC_WO_CHAIN

RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...

@ INTRINSIC_W_CHAIN

RESULT,OUTCHAIN = INTRINSIC_W_CHAIN(INCHAIN, INTRINSICID, arg1, ...) This node represents a target in...

@ SingleThread

Synchronized with respect to signal handlers executing in the same thread.

@ System

Synchronized with respect to all concurrently executing threads.

MCSymbolWasm * getOrCreateFunctionTableSymbol(MCContext &Ctx, const WebAssemblySubtarget *Subtarget)

Returns the __indirect_function_table, for use in call_indirect and in function bitcasts.

cl::opt< bool > WasmUseLegacyEH

NodeAddr< NodeBase * > Node

This is an optimization pass for GlobalISel generic memory operations.

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

FunctionPass * createWebAssemblyISelDag(WebAssemblyTargetMachine &TM, CodeGenOptLevel OptLevel)

This pass converts a legalized DAG into a WebAssembly-specific DAG, ready for instruction scheduling.

Definition WebAssemblyISelDAGToDAG.cpp:553

CodeGenOptLevel

Code generation optimization level.

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

LLVM_ABI raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

DWARFExpression::Operation Op

constexpr unsigned BitWidth

static EVT getIntegerVT(LLVMContext &Context, unsigned BitWidth)

Returns the EVT that represents an integer with the given number of bits.