1111// ===----------------------------------------------------------------------===//
1212
1313#include " WebAssemblyLegalizerInfo.h"
14+ #include " MCTargetDesc/WebAssemblyMCTargetDesc.h"
15+ #include " WebAssemblySubtarget.h"
16+ #include " llvm/CodeGen/GlobalISel/LegalizerHelper.h"
17+ #include " llvm/CodeGen/MachineInstr.h"
18+ #include " llvm/CodeGen/TargetOpcodes.h"
19+ #include " llvm/IR/DerivedTypes.h"
1420
1521#define DEBUG_TYPE " wasm-legalinfo"
1622
@@ -19,5 +25,255 @@ using namespace LegalizeActions;
1925
2026WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo (
2127 const WebAssemblySubtarget &ST) {
28+ using namespace TargetOpcode ;
29+ const LLT s8 = LLT::scalar (8 );
30+ const LLT s16 = LLT::scalar (16 );
31+ const LLT s32 = LLT::scalar (32 );
32+ const LLT s64 = LLT::scalar (64 );
33+
34+ const LLT p0 = LLT::pointer (0 , ST.hasAddr64 () ? 64 : 32 );
35+ const LLT p0s = LLT::scalar (ST.hasAddr64 () ? 64 : 32 );
36+
37+ getActionDefinitionsBuilder (G_GLOBAL_VALUE).legalFor ({p0});
38+
39+ getActionDefinitionsBuilder (G_PHI)
40+ .legalFor ({p0, s32, s64})
41+ .widenScalarToNextPow2 (0 )
42+ .clampScalar (0 , s32, s64);
43+ getActionDefinitionsBuilder (G_BR).alwaysLegal ();
44+ getActionDefinitionsBuilder (G_BRCOND).legalFor ({s32}).clampScalar (0 , s32,
45+ s32);
46+ getActionDefinitionsBuilder (G_BRJT)
47+ .legalFor ({{p0, s32}})
48+ .clampScalar (1 , s32, s32);
49+
50+ getActionDefinitionsBuilder (G_SELECT)
51+ .legalFor ({{s32, s32}, {s64, s32}, {p0, s32}})
52+ .widenScalarToNextPow2 (0 )
53+ .clampScalar (0 , s32, s64)
54+ .clampScalar (1 , s32, s32);
55+
56+ getActionDefinitionsBuilder (G_JUMP_TABLE).legalFor ({p0});
57+
58+ getActionDefinitionsBuilder (G_ICMP)
59+ .legalFor ({{s32, s32}, {s32, s64}, {s32, p0}})
60+ .widenScalarToNextPow2 (1 )
61+ .clampScalar (1 , s32, s64)
62+ .clampScalar (0 , s32, s32);
63+
64+ getActionDefinitionsBuilder (G_FCMP)
65+ .legalFor ({{s32, s32}, {s32, s64}})
66+ .clampScalar (0 , s32, s32)
67+ .libcall ();
68+
69+ getActionDefinitionsBuilder (G_FRAME_INDEX).legalFor ({p0});
70+
71+ getActionDefinitionsBuilder (G_CONSTANT)
72+ .legalFor ({s32, s64, p0})
73+ .widenScalarToNextPow2 (0 )
74+ .clampScalar (0 , s32, s64);
75+
76+ getActionDefinitionsBuilder (G_FCONSTANT)
77+ .legalFor ({s32, s64})
78+ .clampScalar (0 , s32, s64);
79+
80+ getActionDefinitionsBuilder (G_IMPLICIT_DEF)
81+ .legalFor ({s32, s64, p0})
82+ .widenScalarToNextPow2 (0 )
83+ .clampScalar (0 , s32, s64);
84+
85+ getActionDefinitionsBuilder (
86+ {G_ADD, G_SUB, G_MUL, G_UDIV, G_SDIV, G_UREM, G_SREM})
87+ .legalFor ({s32, s64})
88+ .widenScalarToNextPow2 (0 )
89+ .clampScalar (0 , s32, s64);
90+
91+ getActionDefinitionsBuilder ({G_ASHR, G_LSHR, G_SHL, G_CTLZ, G_CTLZ_ZERO_UNDEF,
92+ G_CTTZ, G_CTTZ_ZERO_UNDEF, G_CTPOP, G_FSHL,
93+ G_FSHR})
94+ .legalFor ({{s32, s32}, {s64, s64}})
95+ .widenScalarToNextPow2 (0 )
96+ .clampScalar (0 , s32, s64)
97+ .minScalarSameAs (1 , 0 )
98+ .maxScalarSameAs (1 , 0 );
99+
100+ getActionDefinitionsBuilder ({G_SCMP, G_UCMP}).lower ();
101+
102+ getActionDefinitionsBuilder ({G_AND, G_OR, G_XOR})
103+ .legalFor ({s32, s64})
104+ .widenScalarToNextPow2 (0 )
105+ .clampScalar (0 , s32, s64);
106+
107+ getActionDefinitionsBuilder ({G_UMIN, G_UMAX, G_SMIN, G_SMAX}).lower ();
108+
109+ getActionDefinitionsBuilder ({G_FADD, G_FSUB, G_FDIV, G_FMUL, G_FNEG, G_FABS,
110+ G_FCEIL, G_FFLOOR, G_FSQRT, G_INTRINSIC_TRUNC,
111+ G_FNEARBYINT, G_FRINT, G_INTRINSIC_ROUNDEVEN,
112+ G_FMINIMUM, G_FMAXIMUM})
113+ .legalFor ({s32, s64})
114+ .minScalar (0 , s32);
115+
116+ // TODO: _IEEE not lowering correctly?
117+ getActionDefinitionsBuilder (
118+ {G_FMINNUM, G_FMAXNUM, G_FMINNUM_IEEE, G_FMAXNUM_IEEE})
119+ .lowerFor ({s32, s64})
120+ .minScalar (0 , s32);
121+
122+ getActionDefinitionsBuilder ({G_FMA, G_FREM})
123+ .libcallFor ({s32, s64})
124+ .minScalar (0 , s32);
125+
126+ getActionDefinitionsBuilder (G_FCOPYSIGN)
127+ .legalFor ({s32, s64})
128+ .minScalar (0 , s32)
129+ .minScalarSameAs (1 , 0 )
130+ .maxScalarSameAs (1 , 0 );
131+
132+ getActionDefinitionsBuilder ({G_FPTOUI, G_FPTOUI_SAT, G_FPTOSI, G_FPTOSI_SAT})
133+ .legalForCartesianProduct ({s32, s64}, {s32, s64})
134+ .minScalar (1 , s32)
135+ .widenScalarToNextPow2 (0 )
136+ .clampScalar (0 , s32, s64);
137+
138+ getActionDefinitionsBuilder ({G_UITOFP, G_SITOFP})
139+ .legalForCartesianProduct ({s32, s64}, {s32, s64})
140+ .minScalar (1 , s32)
141+ .widenScalarToNextPow2 (1 )
142+ .clampScalar (1 , s32, s64);
143+
144+ getActionDefinitionsBuilder (G_PTRTOINT).legalFor ({{p0s, p0}});
145+ getActionDefinitionsBuilder (G_INTTOPTR).legalFor ({{p0, p0s}});
146+ getActionDefinitionsBuilder (G_PTR_ADD).legalFor ({{p0, p0s}});
147+
148+ getActionDefinitionsBuilder (G_LOAD)
149+ .legalForTypesWithMemDesc (
150+ {{s32, p0, s32, 1 }, {s64, p0, s64, 1 }, {p0, p0, p0, 1 }})
151+ .legalForTypesWithMemDesc ({{s32, p0, s8, 1 },
152+ {s32, p0, s16, 1 },
153+
154+ {s64, p0, s8, 1 },
155+ {s64, p0, s16, 1 },
156+ {s64, p0, s32, 1 }})
157+ .widenScalarToNextPow2 (0 )
158+ .lowerIfMemSizeNotByteSizePow2 ()
159+ .clampScalar (0 , s32, s64);
160+
161+ getActionDefinitionsBuilder (G_STORE)
162+ .legalForTypesWithMemDesc (
163+ {{s32, p0, s32, 1 }, {s64, p0, s64, 1 }, {p0, p0, p0, 1 }})
164+ .legalForTypesWithMemDesc ({{s32, p0, s8, 1 },
165+ {s32, p0, s16, 1 },
166+
167+ {s64, p0, s8, 1 },
168+ {s64, p0, s16, 1 },
169+ {s64, p0, s32, 1 }})
170+ .widenScalarToNextPow2 (0 )
171+ .lowerIfMemSizeNotByteSizePow2 ()
172+ .clampScalar (0 , s32, s64);
173+
174+ getActionDefinitionsBuilder ({G_ZEXTLOAD, G_SEXTLOAD})
175+ .legalForTypesWithMemDesc ({{s32, p0, s8, 1 },
176+ {s32, p0, s16, 1 },
177+
178+ {s64, p0, s8, 1 },
179+ {s64, p0, s16, 1 },
180+ {s64, p0, s32, 1 }})
181+ .widenScalarToNextPow2 (0 )
182+ .lowerIfMemSizeNotByteSizePow2 ()
183+ .clampScalar (0 , s32, s64)
184+ .lower ();
185+
186+ if (ST.hasBulkMemoryOpt ()) {
187+ getActionDefinitionsBuilder (G_BZERO).unsupported ();
188+
189+ getActionDefinitionsBuilder (G_MEMSET)
190+ .legalForCartesianProduct ({p0}, {s32}, {p0s})
191+ .customForCartesianProduct ({p0}, {s8}, {p0s})
192+ .immIdx (0 );
193+
194+ getActionDefinitionsBuilder ({G_MEMCPY, G_MEMMOVE})
195+ .legalForCartesianProduct ({p0}, {p0}, {p0s})
196+ .immIdx (0 );
197+
198+ getActionDefinitionsBuilder (G_MEMCPY_INLINE)
199+ .legalForCartesianProduct ({p0}, {p0}, {p0s});
200+ } else {
201+ getActionDefinitionsBuilder ({G_BZERO, G_MEMCPY, G_MEMMOVE, G_MEMSET})
202+ .libcall ();
203+ }
204+
205+ // TODO: figure out how to combine G_ANYEXT of G_ASSERT_{S|Z}EXT (or
206+ // appropriate G_AND and G_SEXT_IN_REG?) to a G_{S|Z}EXT + G_ASSERT_{S|Z}EXT
207+ // for better optimization (since G_ANYEXT lowers to a ZEXT or SEXT
208+ // instruction anyway).
209+
210+ getActionDefinitionsBuilder (G_ANYEXT)
211+ .legalFor ({{s64, s32}})
212+ .clampScalar (0 , s32, s64)
213+ .clampScalar (1 , s32, s64);
214+
215+ getActionDefinitionsBuilder ({G_SEXT, G_ZEXT})
216+ .legalFor ({{s64, s32}})
217+ .clampScalar (0 , s32, s64)
218+ .clampScalar (1 , s32, s64)
219+ .lower ();
220+
221+ if (ST.hasSignExt ()) {
222+ getActionDefinitionsBuilder (G_SEXT_INREG)
223+ .clampScalar (0 , s32, s64)
224+ .customFor ({s32, s64})
225+ .lower ();
226+ } else {
227+ getActionDefinitionsBuilder (G_SEXT_INREG).lower ();
228+ }
229+
230+ getActionDefinitionsBuilder (G_TRUNC)
231+ .legalFor ({{s32, s64}})
232+ .clampScalar (0 , s32, s64)
233+ .clampScalar (1 , s32, s64)
234+ .lower ();
235+
236+ getActionDefinitionsBuilder (G_FPEXT).legalFor ({{s64, s32}});
237+
238+ getActionDefinitionsBuilder (G_FPTRUNC).legalFor ({{s32, s64}});
239+
240+ getActionDefinitionsBuilder (G_VASTART).legalFor ({p0});
241+ getActionDefinitionsBuilder (G_VAARG)
242+ .legalForCartesianProduct ({s32, s64}, {p0})
243+ .clampScalar (0 , s32, s64);
244+
22245 getLegacyLegalizerInfo ().computeTables ();
23246}
247+
248+ bool WebAssemblyLegalizerInfo::legalizeCustom (
249+ LegalizerHelper &Helper, MachineInstr &MI,
250+ LostDebugLocObserver &LocObserver) const {
251+ switch (MI.getOpcode ()) {
252+ case TargetOpcode::G_SEXT_INREG: {
253+ // Mark only 8/16/32-bit SEXT_INREG as legal
254+ auto [DstType, SrcType] = MI.getFirst2LLTs ();
255+ auto ExtFromWidth = MI.getOperand (2 ).getImm ();
256+
257+ if (ExtFromWidth == 8 || ExtFromWidth == 16 ||
258+ (DstType.getScalarSizeInBits () == 64 && ExtFromWidth == 32 )) {
259+ return true ;
260+ }
261+ return false ;
262+ }
263+ case TargetOpcode::G_MEMSET: {
264+ // Anyext the value being set to 32 bit (only the bottom 8 bits are read by
265+ // the instruction).
266+ Helper.Observer .changingInstr (MI);
267+ auto &Value = MI.getOperand (1 );
268+
269+ Register ExtValueReg =
270+ Helper.MIRBuilder .buildAnyExt (LLT::scalar (32 ), Value).getReg (0 );
271+ Value.setReg (ExtValueReg);
272+ Helper.Observer .changedInstr (MI);
273+ return true ;
274+ }
275+ default :
276+ break ;
277+ }
278+ return false ;
279+ }
0 commit comments