1//===- WebAssemblyLegalizerInfo.cpp ------------------------------*- 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/// \file
9/// This file implements the targeting of the Machinelegalizer class for
10/// WebAssembly.
11//===----------------------------------------------------------------------===//
12
13#include "WebAssemblyLegalizerInfo.h"
14#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
15#include "WebAssemblySubtarget.h"
16#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
17#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
18
19#define DEBUG_TYPE "wasm-legalinfo"
20
21using namespace llvm;
22using namespace LegalizeActions;
23
24WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo(
25 const WebAssemblySubtarget &ST) {
26 using namespace TargetOpcode;
27
28 const LLT i32 = LLT::integer(SizeInBits: 32);
29 const LLT i64 = LLT::integer(SizeInBits: 64);
30
31 const LLT f32 = LLT::floatIEEE(SizeInBits: 32);
32 const LLT f64 = LLT::floatIEEE(SizeInBits: 64);
33
34 const LLT s32 = LLT::scalar(SizeInBits: 32);
35 const LLT s64 = LLT::scalar(SizeInBits: 64);
36
37 getActionDefinitionsBuilder(Opcode: G_IMPLICIT_DEF)
38 .legalFor(Types: {i32, i64, f32, f64})
39 .widenScalarToNextPow2(TypeIdx: 0)
40 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64);
41
42 getActionDefinitionsBuilder(Opcodes: {G_CONSTANT, G_ADD, G_SUB, G_MUL, G_UDIV, G_SDIV,
43 G_UREM, G_SREM, G_AND, G_OR, G_XOR})
44 .legalFor(Types: {i32, i64})
45 .widenScalarToNextPow2(TypeIdx: 0)
46 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64);
47
48 getActionDefinitionsBuilder(Opcodes: {G_ASHR, G_LSHR, G_SHL})
49 .legalFor(Types: {{i32, i32}, {i64, i64}})
50 .widenScalarToNextPow2(TypeIdx: 0)
51 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
52 .scalarSameSizeAs(TypeIdx: 1, SameSizeIdx: 0);
53
54 getActionDefinitionsBuilder(Opcodes: {G_CTLZ, G_CTTZ, G_CTPOP})
55 .legalFor(Types: {{i32, i32}, {i64, i64}})
56 .widenScalarToNextPow2(TypeIdx: 1)
57 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64)
58 .scalarSameSizeAs(TypeIdx: 0, SameSizeIdx: 1);
59
60 getActionDefinitionsBuilder(Opcodes: {G_CTLZ_ZERO_POISON, G_CTTZ_ZERO_POISON}).lower();
61
62 getActionDefinitionsBuilder(Opcodes: {G_ROTL, G_ROTR})
63 .legalFor(Types: {{i32, i32}, {i64, i64}})
64 .scalarSameSizeAs(TypeIdx: 1, SameSizeIdx: 0)
65 .lower();
66
67 getActionDefinitionsBuilder(Opcodes: {G_FSHL, G_FSHR}).lower();
68
69 getActionDefinitionsBuilder(Opcode: G_ICMP)
70 .legalForCartesianProduct(Types0: {i32}, Types1: {i32, i64})
71 .widenScalarToNextPow2(TypeIdx: 1)
72 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s32)
73 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64);
74
75 getActionDefinitionsBuilder(Opcodes: {G_UMIN, G_UMAX, G_SMIN, G_SMAX}).lower();
76
77 getActionDefinitionsBuilder(Opcodes: {G_SCMP, G_UCMP}).lower();
78
79 getActionDefinitionsBuilder(Opcodes: {G_ANYEXT, G_SEXT, G_ZEXT})
80 .legalFor(Types: {{i64, i32}})
81 .clampScalar(TypeIdx: 0, MinTy: s64, MaxTy: s64)
82 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s32);
83
84 getActionDefinitionsBuilder(Opcode: G_TRUNC)
85 .legalFor(Types: {{i32, i64}})
86 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s32)
87 .clampScalar(TypeIdx: 1, MinTy: s64, MaxTy: s64);
88
89 getActionDefinitionsBuilder(Opcode: G_SEXT_INREG)
90 .customFor(Pred: ST.hasSignExt(), Types: {i32, i64})
91 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
92 .lower();
93
94 getActionDefinitionsBuilder(Opcodes: {G_FCONSTANT, G_FABS, G_FNEG, G_FCEIL, G_FFLOOR,
95 G_INTRINSIC_TRUNC, G_FNEARBYINT, G_FRINT,
96 G_INTRINSIC_ROUNDEVEN, G_FSQRT, G_FADD, G_FSUB,
97 G_FMUL, G_FDIV})
98 .legalFor(Types: {f32, f64})
99 .minScalar(TypeIdx: 0, Ty: s32);
100
101 getActionDefinitionsBuilder(Opcode: G_FCOPYSIGN)
102 .legalFor(Types: {f32, f64})
103 .minScalar(TypeIdx: 0, Ty: s32)
104 .scalarSameSizeAs(TypeIdx: 1, SameSizeIdx: 0);
105
106 getActionDefinitionsBuilder(Opcode: G_FPEXT)
107 .legalFor(Types: {{f64, f32}})
108 .clampScalar(TypeIdx: 0, MinTy: s64, MaxTy: s64)
109 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s32);
110
111 getActionDefinitionsBuilder(Opcode: G_FPTRUNC)
112 .legalFor(Types: {{f32, f64}})
113 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s32)
114 .clampScalar(TypeIdx: 1, MinTy: s64, MaxTy: s64);
115
116 getActionDefinitionsBuilder(Opcode: G_BITCAST)
117 .legalFor(Types: {{i32, f32}, {f32, i32}, {i64, f64}, {f64, i64}})
118 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
119 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64);
120
121 getActionDefinitionsBuilder(Opcodes: {G_FPTOSI, G_FPTOUI})
122 .legalForCartesianProduct(Types0: {i32, i64}, Types1: {f32, f64})
123 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
124 .minScalar(TypeIdx: 1, Ty: s32);
125
126 // TODO: once comparison ops are in place
127 /*if (ST.hasNontrappingFPToInt()) {
128 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
129 .legalForCartesianProduct({i32, i64}, {f32, f64})
130 .clampScalar(0, s32, s64)
131 .minScalar(1, s32);
132 } else {
133 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
134 .lowerForCartesianProduct({i32, i64}, {f32, f64})
135 .clampScalar(0, s32, s64)
136 .minScalar(1, s32);
137 }*/
138
139 getActionDefinitionsBuilder(Opcodes: {G_SITOFP, G_UITOFP})
140 .legalForCartesianProduct(Types0: {f32, f64}, Types1: {i32, i64})
141 .minScalar(TypeIdx: 0, Ty: s32)
142 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64);
143
144 getActionDefinitionsBuilder(Opcode: G_SELECT)
145 .legalForCartesianProduct(Types0: {i32, i64, f32, f64}, Types1: {i32})
146 .widenScalarToNextPow2(TypeIdx: 0)
147 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
148 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s32);
149}
150
151bool WebAssemblyLegalizerInfo::legalizeCustom(
152 LegalizerHelper &Helper, MachineInstr &MI,
153 LostDebugLocObserver &LocObserver) const {
154 switch (MI.getOpcode()) {
155 case TargetOpcode::G_SEXT_INREG: {
156 assert(MI.getOperand(2).isImm() && "Expected immediate");
157
158 // Mark only 8/16/32-bit SEXT_INREG as legal
159 auto [DstType, SrcType] = MI.getFirst2LLTs();
160 auto ExtFromWidth = MI.getOperand(i: 2).getImm();
161
162 if (ExtFromWidth == 8 || ExtFromWidth == 16 ||
163 (DstType.getScalarSizeInBits() == 64 && ExtFromWidth == 32)) {
164 return true;
165 }
166
167 return Helper.lower(MI, TypeIdx: 0, Ty: DstType) != LegalizerHelper::UnableToLegalize;
168 }
169 default:
170 break;
171 }
172 return false;
173}
174