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;
23using namespace LegalityPredicates;
24
25WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo(
26 const WebAssemblySubtarget &ST) {
27 using namespace TargetOpcode;
28
29 const LLT i8 = LLT::integer(SizeInBits: 8);
30 const LLT i16 = LLT::integer(SizeInBits: 16);
31 const LLT i32 = LLT::integer(SizeInBits: 32);
32 const LLT i64 = LLT::integer(SizeInBits: 64);
33
34 const LLT f32 = LLT::floatIEEE(SizeInBits: 32);
35 const LLT f64 = LLT::floatIEEE(SizeInBits: 64);
36
37 const LLT s32 = LLT::scalar(SizeInBits: 32);
38 const LLT s64 = LLT::scalar(SizeInBits: 64);
39
40 const LLT p0 = LLT::pointer(AddressSpace: 0, SizeInBits: ST.hasAddr64() ? 64 : 32);
41 const LLT p0i = LLT::integer(SizeInBits: ST.hasAddr64() ? 64 : 32);
42 const LLT p0s = LLT::scalar(SizeInBits: ST.hasAddr64() ? 64 : 32);
43
44 getActionDefinitionsBuilder(Opcode: G_IMPLICIT_DEF)
45 .legalFor(Types: {i32, i64, f32, f64, p0})
46 .widenScalarToNextPow2(TypeIdx: 0)
47 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64);
48
49 getActionDefinitionsBuilder(Opcode: G_CONSTANT)
50 .legalFor(Types: {i32, i64, p0})
51 .widenScalarToNextPow2(TypeIdx: 0)
52 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64);
53
54 getActionDefinitionsBuilder(
55 Opcodes: {G_ADD, G_SUB, G_MUL, G_UDIV, G_SDIV, G_UREM, G_SREM, G_AND, G_OR, G_XOR})
56 .legalFor(Types: {i32, i64})
57 .widenScalarToNextPow2(TypeIdx: 0)
58 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64);
59
60 getActionDefinitionsBuilder(Opcodes: {G_ASHR, G_LSHR, G_SHL})
61 .legalFor(Types: {{i32, i32}, {i64, i64}})
62 .widenScalarToNextPow2(TypeIdx: 0)
63 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
64 .scalarSameSizeAs(TypeIdx: 1, SameSizeIdx: 0);
65
66 getActionDefinitionsBuilder(Opcodes: {G_CTLZ, G_CTTZ, G_CTPOP})
67 .legalFor(Types: {{i32, i32}, {i64, i64}})
68 .widenScalarToNextPow2(TypeIdx: 1)
69 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64)
70 .scalarSameSizeAs(TypeIdx: 0, SameSizeIdx: 1);
71
72 getActionDefinitionsBuilder(Opcodes: {G_CTLZ_ZERO_POISON, G_CTTZ_ZERO_POISON}).lower();
73
74 getActionDefinitionsBuilder(Opcodes: {G_ROTL, G_ROTR})
75 .legalFor(Types: {{i32, i32}, {i64, i64}})
76 .scalarSameSizeAs(TypeIdx: 1, SameSizeIdx: 0)
77 .lower();
78
79 getActionDefinitionsBuilder(Opcodes: {G_FSHL, G_FSHR}).lower();
80
81 getActionDefinitionsBuilder(Opcode: G_ICMP)
82 .legalForCartesianProduct(Types0: {i32}, Types1: {i32, i64, p0})
83 .widenScalarToNextPow2(TypeIdx: 1)
84 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s32)
85 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64);
86
87 getActionDefinitionsBuilder(Opcodes: {G_UMIN, G_UMAX, G_SMIN, G_SMAX}).lower();
88
89 getActionDefinitionsBuilder(Opcodes: {G_SCMP, G_UCMP}).lower();
90
91 getActionDefinitionsBuilder(Opcodes: {G_ANYEXT, G_SEXT, G_ZEXT})
92 .legalFor(Types: {{i64, i32}})
93 .clampScalar(TypeIdx: 0, MinTy: s64, MaxTy: s64)
94 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s32);
95
96 getActionDefinitionsBuilder(Opcode: G_TRUNC)
97 .legalFor(Types: {{i32, i64}})
98 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s32)
99 .clampScalar(TypeIdx: 1, MinTy: s64, MaxTy: s64);
100
101 {
102 LegalizeRuleSet &Builder = getActionDefinitionsBuilder(Opcode: G_SEXT_INREG);
103
104 if (ST.hasSignExt())
105 Builder.legalIf(
106 Predicate: all(P0: typeInSet(TypeIdx: 0, TypesInit: {i32, i64}),
107 P1: LegalityPredicates::any(P0: immInSet(ImmIdx: 0, ImmsInit: {8, 16}),
108 P1: all(P0: typeIs(TypeIdx: 0, TypesInit: i64), P1: immIs(ImmIdx: 0, Imm: 32)))));
109
110 Builder.clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64).lower();
111 }
112
113 getActionDefinitionsBuilder(Opcodes: {G_FCONSTANT, G_FABS, G_FNEG, G_FCEIL, G_FFLOOR,
114 G_INTRINSIC_TRUNC, G_FNEARBYINT, G_FRINT,
115 G_INTRINSIC_ROUNDEVEN, G_FSQRT, G_FADD, G_FSUB,
116 G_FMUL, G_FDIV})
117 .legalFor(Types: {f32, f64})
118 .minScalar(TypeIdx: 0, Ty: s32);
119
120 getActionDefinitionsBuilder(Opcode: G_FCOPYSIGN)
121 .legalFor(Types: {f32, f64})
122 .minScalar(TypeIdx: 0, Ty: s32)
123 .scalarSameSizeAs(TypeIdx: 1, SameSizeIdx: 0);
124
125 getActionDefinitionsBuilder(Opcode: G_FPEXT)
126 .legalFor(Types: {{f64, f32}})
127 .clampScalar(TypeIdx: 0, MinTy: s64, MaxTy: s64)
128 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s32);
129
130 getActionDefinitionsBuilder(Opcode: G_FPTRUNC)
131 .legalFor(Types: {{f32, f64}})
132 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s32)
133 .clampScalar(TypeIdx: 1, MinTy: s64, MaxTy: s64);
134
135 getActionDefinitionsBuilder(Opcode: G_BITCAST)
136 .legalFor(Types: {{i32, f32}, {f32, i32}, {i64, f64}, {f64, i64}})
137 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
138 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64);
139
140 getActionDefinitionsBuilder(Opcodes: {G_FPTOSI, G_FPTOUI})
141 .legalForCartesianProduct(Types0: {i32, i64}, Types1: {f32, f64})
142 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
143 .minScalar(TypeIdx: 1, Ty: s32);
144
145 // TODO: once comparison ops are in place
146 /*if (ST.hasNontrappingFPToInt()) {
147 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
148 .legalForCartesianProduct({i32, i64}, {f32, f64})
149 .clampScalar(0, s32, s64)
150 .minScalar(1, s32);
151 } else {
152 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
153 .lowerForCartesianProduct({i32, i64}, {f32, f64})
154 .clampScalar(0, s32, s64)
155 .minScalar(1, s32);
156 }*/
157
158 getActionDefinitionsBuilder(Opcodes: {G_SITOFP, G_UITOFP})
159 .legalForCartesianProduct(Types0: {f32, f64}, Types1: {i32, i64})
160 .minScalar(TypeIdx: 0, Ty: s32)
161 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s64);
162
163 getActionDefinitionsBuilder(Opcode: G_SELECT)
164 .legalForCartesianProduct(Types0: {i32, i64, f32, f64, p0}, Types1: {i32})
165 .widenScalarToNextPow2(TypeIdx: 0)
166 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
167 .clampScalar(TypeIdx: 1, MinTy: s32, MaxTy: s32);
168
169 getActionDefinitionsBuilder(Opcode: G_PTRTOINT)
170 .legalFor(Types: {{p0i, p0}})
171 .clampScalar(TypeIdx: 0, MinTy: p0s, MaxTy: p0s);
172 getActionDefinitionsBuilder(Opcode: G_INTTOPTR)
173 .legalFor(Types: {{p0, p0i}})
174 .clampScalar(TypeIdx: 1, MinTy: p0s, MaxTy: p0s);
175
176 getActionDefinitionsBuilder(Opcodes: {G_PTR_ADD, G_PTRMASK})
177 .legalFor(Types: {{p0, p0i}})
178 .clampScalar(TypeIdx: 1, MinTy: p0s, MaxTy: p0s);
179
180 getActionDefinitionsBuilder(Opcodes: {G_FRAME_INDEX, G_GLOBAL_VALUE}).legalFor(Types: {p0});
181
182 getActionDefinitionsBuilder(Opcode: G_LOAD)
183 .legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: i32, .Type1: p0, .MemTy: i8, .Align: 1},
184 {.Type0: i32, .Type1: p0, .MemTy: i16, .Align: 1},
185 {.Type0: i32, .Type1: p0, .MemTy: i32, .Align: 1},
186
187 {.Type0: i64, .Type1: p0, .MemTy: i8, .Align: 1},
188 {.Type0: i64, .Type1: p0, .MemTy: i16, .Align: 1},
189 {.Type0: i64, .Type1: p0, .MemTy: i32, .Align: 1},
190 {.Type0: i64, .Type1: p0, .MemTy: i64, .Align: 1},
191
192 {.Type0: f32, .Type1: p0, .MemTy: f32, .Align: 1},
193 {.Type0: f64, .Type1: p0, .MemTy: f64, .Align: 1},
194
195 {.Type0: p0, .Type1: p0, .MemTy: p0, .Align: 1}})
196 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
197 .lowerIfMemSizeNotByteSizePow2();
198
199 getActionDefinitionsBuilder(Opcodes: {G_ZEXTLOAD, G_SEXTLOAD})
200 .legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: i32, .Type1: p0, .MemTy: i8, .Align: 1},
201 {.Type0: i32, .Type1: p0, .MemTy: i16, .Align: 1},
202
203 {.Type0: i64, .Type1: p0, .MemTy: i8, .Align: 1},
204 {.Type0: i64, .Type1: p0, .MemTy: i16, .Align: 1},
205 {.Type0: i64, .Type1: p0, .MemTy: i32, .Align: 1}})
206 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
207 .lowerIfMemSizeNotByteSizePow2();
208
209 getActionDefinitionsBuilder(Opcode: G_STORE)
210 .legalForTypesWithMemDesc(TypesAndMemDesc: {{.Type0: i32, .Type1: p0, .MemTy: i8, .Align: 1},
211 {.Type0: i32, .Type1: p0, .MemTy: i16, .Align: 1},
212 {.Type0: i32, .Type1: p0, .MemTy: i32, .Align: 1},
213
214 {.Type0: i64, .Type1: p0, .MemTy: i8, .Align: 1},
215 {.Type0: i64, .Type1: p0, .MemTy: i16, .Align: 1},
216 {.Type0: i64, .Type1: p0, .MemTy: i32, .Align: 1},
217 {.Type0: i64, .Type1: p0, .MemTy: i64, .Align: 1},
218
219 {.Type0: f32, .Type1: p0, .MemTy: f32, .Align: 1},
220 {.Type0: f64, .Type1: p0, .MemTy: f64, .Align: 1},
221
222 {.Type0: p0, .Type1: p0, .MemTy: p0, .Align: 1}})
223 .clampScalar(TypeIdx: 0, MinTy: s32, MaxTy: s64)
224 .lowerIfMemSizeNotByteSizePow2();
225}
226
227bool WebAssemblyLegalizerInfo::legalizeCustom(
228 LegalizerHelper &Helper, MachineInstr &MI,
229 LostDebugLocObserver &LocObserver) const {
230 switch (MI.getOpcode()) {
231 default:
232 break;
233 }
234 return false;
235}
236