1 | //===-- WebAssemblySelectionDAGInfo.cpp - WebAssembly SelectionDAG Info ---===// |
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 implements the WebAssemblySelectionDAGInfo class. |
11 | /// |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "WebAssemblyTargetMachine.h" |
15 | using namespace llvm; |
16 | |
17 | #define DEBUG_TYPE "wasm-selectiondag-info" |
18 | |
19 | WebAssemblySelectionDAGInfo::~WebAssemblySelectionDAGInfo() = default; // anchor |
20 | |
21 | bool WebAssemblySelectionDAGInfo::isTargetMemoryOpcode(unsigned Opcode) const { |
22 | switch (static_cast<WebAssemblyISD::NodeType>(Opcode)) { |
23 | default: |
24 | return false; |
25 | case WebAssemblyISD::GLOBAL_GET: |
26 | case WebAssemblyISD::GLOBAL_SET: |
27 | case WebAssemblyISD::TABLE_GET: |
28 | case WebAssemblyISD::TABLE_SET: |
29 | return true; |
30 | } |
31 | } |
32 | |
33 | SDValue WebAssemblySelectionDAGInfo::EmitTargetCodeForMemcpy( |
34 | SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Src, |
35 | SDValue Size, Align Alignment, bool IsVolatile, bool AlwaysInline, |
36 | MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const { |
37 | auto &ST = DAG.getMachineFunction().getSubtarget<WebAssemblySubtarget>(); |
38 | if (!ST.hasBulkMemoryOpt()) |
39 | return SDValue(); |
40 | |
41 | SDValue MemIdx = DAG.getConstant(Val: 0, DL, VT: MVT::i32); |
42 | auto LenMVT = ST.hasAddr64() ? MVT::i64 : MVT::i32; |
43 | |
44 | // Use `MEMCPY` here instead of `MEMORY_COPY` because `memory.copy` traps |
45 | // if the pointers are invalid even if the length is zero. `MEMCPY` gets |
46 | // extra code to handle this in the way that LLVM IR expects. |
47 | return DAG.getNode( |
48 | Opcode: WebAssemblyISD::MEMCPY, DL, VT: MVT::Other, |
49 | Ops: {Chain, MemIdx, MemIdx, Dst, Src, DAG.getZExtOrTrunc(Op: Size, DL, VT: LenMVT)}); |
50 | } |
51 | |
52 | SDValue WebAssemblySelectionDAGInfo::EmitTargetCodeForMemmove( |
53 | SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Op1, SDValue Op2, |
54 | SDValue Op3, Align Alignment, bool IsVolatile, |
55 | MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo) const { |
56 | return EmitTargetCodeForMemcpy(DAG, DL, Chain, Dst: Op1, Src: Op2, Size: Op3, |
57 | Alignment, IsVolatile, AlwaysInline: false, |
58 | DstPtrInfo, SrcPtrInfo); |
59 | } |
60 | |
61 | SDValue WebAssemblySelectionDAGInfo::EmitTargetCodeForMemset( |
62 | SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue Val, |
63 | SDValue Size, Align Alignment, bool IsVolatile, bool AlwaysInline, |
64 | MachinePointerInfo DstPtrInfo) const { |
65 | auto &ST = DAG.getMachineFunction().getSubtarget<WebAssemblySubtarget>(); |
66 | if (!ST.hasBulkMemoryOpt()) |
67 | return SDValue(); |
68 | |
69 | SDValue MemIdx = DAG.getConstant(Val: 0, DL, VT: MVT::i32); |
70 | auto LenMVT = ST.hasAddr64() ? MVT::i64 : MVT::i32; |
71 | |
72 | // Use `MEMSET` here instead of `MEMORY_FILL` because `memory.fill` traps |
73 | // if the pointers are invalid even if the length is zero. `MEMSET` gets |
74 | // extra code to handle this in the way that LLVM IR expects. |
75 | // |
76 | // Only low byte matters for val argument, so anyext the i8 |
77 | return DAG.getNode(Opcode: WebAssemblyISD::MEMSET, DL, VT: MVT::Other, N1: Chain, N2: MemIdx, N3: Dst, |
78 | N4: DAG.getAnyExtOrTrunc(Op: Val, DL, VT: MVT::i32), |
79 | N5: DAG.getZExtOrTrunc(Op: Size, DL, VT: LenMVT)); |
80 | } |
81 | |