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