11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#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"
14
20
15
21
#define DEBUG_TYPE " wasm-legalinfo"
16
22
@@ -19,5 +25,255 @@ using namespace LegalizeActions;
19
25
20
26
WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo (
21
27
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
+
22
245
getLegacyLegalizerInfo ().computeTables ();
23
246
}
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