1 //===-- WebAssembly.cpp - Emit LLVM Code for builtins ---------------------===// 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 // 9 // This contains code to emit Builtin calls as LLVM code. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CGBuiltin.h" 14 #include "clang/Basic/TargetBuiltins.h" 15 #include "llvm/IR/IntrinsicsWebAssembly.h" 16 17 using namespace clang; 18 using namespace CodeGen; 19 using namespace llvm; 20 21 Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, 22 const CallExpr *E) { 23 switch (BuiltinID) { 24 case WebAssembly::BI__builtin_wasm_memory_size: { 25 llvm::Type *ResultType = ConvertType(E->getType()); 26 Value *I = EmitScalarExpr(E->getArg(0)); 27 Function *Callee = 28 CGM.getIntrinsic(Intrinsic::wasm_memory_size, ResultType); 29 return Builder.CreateCall(Callee, I); 30 } 31 case WebAssembly::BI__builtin_wasm_memory_grow: { 32 llvm::Type *ResultType = ConvertType(E->getType()); 33 Value *Args[] = {EmitScalarExpr(E->getArg(0)), 34 EmitScalarExpr(E->getArg(1))}; 35 Function *Callee = 36 CGM.getIntrinsic(Intrinsic::wasm_memory_grow, ResultType); 37 return Builder.CreateCall(Callee, Args); 38 } 39 case WebAssembly::BI__builtin_wasm_tls_size: { 40 llvm::Type *ResultType = ConvertType(E->getType()); 41 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType); 42 return Builder.CreateCall(Callee); 43 } 44 case WebAssembly::BI__builtin_wasm_tls_align: { 45 llvm::Type *ResultType = ConvertType(E->getType()); 46 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_align, ResultType); 47 return Builder.CreateCall(Callee); 48 } 49 case WebAssembly::BI__builtin_wasm_tls_base: { 50 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base); 51 return Builder.CreateCall(Callee); 52 } 53 case WebAssembly::BI__builtin_wasm_throw: { 54 Value *Tag = EmitScalarExpr(E->getArg(0)); 55 Value *Obj = EmitScalarExpr(E->getArg(1)); 56 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw); 57 return EmitRuntimeCallOrInvoke(Callee, {Tag, Obj}); 58 } 59 case WebAssembly::BI__builtin_wasm_rethrow: { 60 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow); 61 return EmitRuntimeCallOrInvoke(Callee); 62 } 63 case WebAssembly::BI__builtin_wasm_memory_atomic_wait32: { 64 Value *Addr = EmitScalarExpr(E->getArg(0)); 65 Value *Expected = EmitScalarExpr(E->getArg(1)); 66 Value *Timeout = EmitScalarExpr(E->getArg(2)); 67 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait32); 68 return Builder.CreateCall(Callee, {Addr, Expected, Timeout}); 69 } 70 case WebAssembly::BI__builtin_wasm_memory_atomic_wait64: { 71 Value *Addr = EmitScalarExpr(E->getArg(0)); 72 Value *Expected = EmitScalarExpr(E->getArg(1)); 73 Value *Timeout = EmitScalarExpr(E->getArg(2)); 74 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait64); 75 return Builder.CreateCall(Callee, {Addr, Expected, Timeout}); 76 } 77 case WebAssembly::BI__builtin_wasm_memory_atomic_notify: { 78 Value *Addr = EmitScalarExpr(E->getArg(0)); 79 Value *Count = EmitScalarExpr(E->getArg(1)); 80 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_notify); 81 return Builder.CreateCall(Callee, {Addr, Count}); 82 } 83 case WebAssembly::BI__builtin_wasm_trunc_s_i32_f32: 84 case WebAssembly::BI__builtin_wasm_trunc_s_i32_f64: 85 case WebAssembly::BI__builtin_wasm_trunc_s_i64_f32: 86 case WebAssembly::BI__builtin_wasm_trunc_s_i64_f64: { 87 Value *Src = EmitScalarExpr(E->getArg(0)); 88 llvm::Type *ResT = ConvertType(E->getType()); 89 Function *Callee = 90 CGM.getIntrinsic(Intrinsic::wasm_trunc_signed, {ResT, Src->getType()}); 91 return Builder.CreateCall(Callee, {Src}); 92 } 93 case WebAssembly::BI__builtin_wasm_trunc_u_i32_f32: 94 case WebAssembly::BI__builtin_wasm_trunc_u_i32_f64: 95 case WebAssembly::BI__builtin_wasm_trunc_u_i64_f32: 96 case WebAssembly::BI__builtin_wasm_trunc_u_i64_f64: { 97 Value *Src = EmitScalarExpr(E->getArg(0)); 98 llvm::Type *ResT = ConvertType(E->getType()); 99 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_unsigned, 100 {ResT, Src->getType()}); 101 return Builder.CreateCall(Callee, {Src}); 102 } 103 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32: 104 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64: 105 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32: 106 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f64: 107 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i16x8_f16x8: 108 case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32x4_f32x4: { 109 Value *Src = EmitScalarExpr(E->getArg(0)); 110 llvm::Type *ResT = ConvertType(E->getType()); 111 Function *Callee = 112 CGM.getIntrinsic(Intrinsic::fptosi_sat, {ResT, Src->getType()}); 113 return Builder.CreateCall(Callee, {Src}); 114 } 115 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f32: 116 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f64: 117 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f32: 118 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f64: 119 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i16x8_f16x8: 120 case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32x4_f32x4: { 121 Value *Src = EmitScalarExpr(E->getArg(0)); 122 llvm::Type *ResT = ConvertType(E->getType()); 123 Function *Callee = 124 CGM.getIntrinsic(Intrinsic::fptoui_sat, {ResT, Src->getType()}); 125 return Builder.CreateCall(Callee, {Src}); 126 } 127 case WebAssembly::BI__builtin_wasm_min_f32: 128 case WebAssembly::BI__builtin_wasm_min_f64: 129 case WebAssembly::BI__builtin_wasm_min_f16x8: 130 case WebAssembly::BI__builtin_wasm_min_f32x4: 131 case WebAssembly::BI__builtin_wasm_min_f64x2: { 132 Value *LHS = EmitScalarExpr(E->getArg(0)); 133 Value *RHS = EmitScalarExpr(E->getArg(1)); 134 Function *Callee = 135 CGM.getIntrinsic(Intrinsic::minimum, ConvertType(E->getType())); 136 return Builder.CreateCall(Callee, {LHS, RHS}); 137 } 138 case WebAssembly::BI__builtin_wasm_max_f32: 139 case WebAssembly::BI__builtin_wasm_max_f64: 140 case WebAssembly::BI__builtin_wasm_max_f16x8: 141 case WebAssembly::BI__builtin_wasm_max_f32x4: 142 case WebAssembly::BI__builtin_wasm_max_f64x2: { 143 Value *LHS = EmitScalarExpr(E->getArg(0)); 144 Value *RHS = EmitScalarExpr(E->getArg(1)); 145 Function *Callee = 146 CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType())); 147 return Builder.CreateCall(Callee, {LHS, RHS}); 148 } 149 case WebAssembly::BI__builtin_wasm_pmin_f16x8: 150 case WebAssembly::BI__builtin_wasm_pmin_f32x4: 151 case WebAssembly::BI__builtin_wasm_pmin_f64x2: { 152 Value *LHS = EmitScalarExpr(E->getArg(0)); 153 Value *RHS = EmitScalarExpr(E->getArg(1)); 154 Function *Callee = 155 CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType())); 156 return Builder.CreateCall(Callee, {LHS, RHS}); 157 } 158 case WebAssembly::BI__builtin_wasm_pmax_f16x8: 159 case WebAssembly::BI__builtin_wasm_pmax_f32x4: 160 case WebAssembly::BI__builtin_wasm_pmax_f64x2: { 161 Value *LHS = EmitScalarExpr(E->getArg(0)); 162 Value *RHS = EmitScalarExpr(E->getArg(1)); 163 Function *Callee = 164 CGM.getIntrinsic(Intrinsic::wasm_pmax, ConvertType(E->getType())); 165 return Builder.CreateCall(Callee, {LHS, RHS}); 166 } 167 case WebAssembly::BI__builtin_wasm_ceil_f16x8: 168 case WebAssembly::BI__builtin_wasm_floor_f16x8: 169 case WebAssembly::BI__builtin_wasm_trunc_f16x8: 170 case WebAssembly::BI__builtin_wasm_nearest_f16x8: 171 case WebAssembly::BI__builtin_wasm_ceil_f32x4: 172 case WebAssembly::BI__builtin_wasm_floor_f32x4: 173 case WebAssembly::BI__builtin_wasm_trunc_f32x4: 174 case WebAssembly::BI__builtin_wasm_nearest_f32x4: 175 case WebAssembly::BI__builtin_wasm_ceil_f64x2: 176 case WebAssembly::BI__builtin_wasm_floor_f64x2: 177 case WebAssembly::BI__builtin_wasm_trunc_f64x2: 178 case WebAssembly::BI__builtin_wasm_nearest_f64x2: { 179 unsigned IntNo; 180 switch (BuiltinID) { 181 case WebAssembly::BI__builtin_wasm_ceil_f16x8: 182 case WebAssembly::BI__builtin_wasm_ceil_f32x4: 183 case WebAssembly::BI__builtin_wasm_ceil_f64x2: 184 IntNo = Intrinsic::ceil; 185 break; 186 case WebAssembly::BI__builtin_wasm_floor_f16x8: 187 case WebAssembly::BI__builtin_wasm_floor_f32x4: 188 case WebAssembly::BI__builtin_wasm_floor_f64x2: 189 IntNo = Intrinsic::floor; 190 break; 191 case WebAssembly::BI__builtin_wasm_trunc_f16x8: 192 case WebAssembly::BI__builtin_wasm_trunc_f32x4: 193 case WebAssembly::BI__builtin_wasm_trunc_f64x2: 194 IntNo = Intrinsic::trunc; 195 break; 196 case WebAssembly::BI__builtin_wasm_nearest_f16x8: 197 case WebAssembly::BI__builtin_wasm_nearest_f32x4: 198 case WebAssembly::BI__builtin_wasm_nearest_f64x2: 199 IntNo = Intrinsic::nearbyint; 200 break; 201 default: 202 llvm_unreachable("unexpected builtin ID"); 203 } 204 Value *Value = EmitScalarExpr(E->getArg(0)); 205 Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType())); 206 return Builder.CreateCall(Callee, Value); 207 } 208 case WebAssembly::BI__builtin_wasm_ref_null_extern: { 209 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_extern); 210 return Builder.CreateCall(Callee); 211 } 212 case WebAssembly::BI__builtin_wasm_ref_is_null_extern: { 213 Value *Src = EmitScalarExpr(E->getArg(0)); 214 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_is_null_extern); 215 return Builder.CreateCall(Callee, {Src}); 216 } 217 case WebAssembly::BI__builtin_wasm_ref_null_func: { 218 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func); 219 return Builder.CreateCall(Callee); 220 } 221 case WebAssembly::BI__builtin_wasm_swizzle_i8x16: { 222 Value *Src = EmitScalarExpr(E->getArg(0)); 223 Value *Indices = EmitScalarExpr(E->getArg(1)); 224 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_swizzle); 225 return Builder.CreateCall(Callee, {Src, Indices}); 226 } 227 case WebAssembly::BI__builtin_wasm_abs_i8x16: 228 case WebAssembly::BI__builtin_wasm_abs_i16x8: 229 case WebAssembly::BI__builtin_wasm_abs_i32x4: 230 case WebAssembly::BI__builtin_wasm_abs_i64x2: { 231 Value *Vec = EmitScalarExpr(E->getArg(0)); 232 Value *Neg = Builder.CreateNeg(Vec, "neg"); 233 Constant *Zero = llvm::Constant::getNullValue(Vec->getType()); 234 Value *ICmp = Builder.CreateICmpSLT(Vec, Zero, "abscond"); 235 return Builder.CreateSelect(ICmp, Neg, Vec, "abs"); 236 } 237 case WebAssembly::BI__builtin_wasm_avgr_u_i8x16: 238 case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: { 239 Value *LHS = EmitScalarExpr(E->getArg(0)); 240 Value *RHS = EmitScalarExpr(E->getArg(1)); 241 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_avgr_unsigned, 242 ConvertType(E->getType())); 243 return Builder.CreateCall(Callee, {LHS, RHS}); 244 } 245 case WebAssembly::BI__builtin_wasm_q15mulr_sat_s_i16x8: { 246 Value *LHS = EmitScalarExpr(E->getArg(0)); 247 Value *RHS = EmitScalarExpr(E->getArg(1)); 248 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_q15mulr_sat_signed); 249 return Builder.CreateCall(Callee, {LHS, RHS}); 250 } 251 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8: 252 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8: 253 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4: 254 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: { 255 Value *Vec = EmitScalarExpr(E->getArg(0)); 256 unsigned IntNo; 257 switch (BuiltinID) { 258 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8: 259 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4: 260 IntNo = Intrinsic::wasm_extadd_pairwise_signed; 261 break; 262 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8: 263 case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: 264 IntNo = Intrinsic::wasm_extadd_pairwise_unsigned; 265 break; 266 default: 267 llvm_unreachable("unexpected builtin ID"); 268 } 269 270 Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType())); 271 return Builder.CreateCall(Callee, Vec); 272 } 273 case WebAssembly::BI__builtin_wasm_bitselect: { 274 Value *V1 = EmitScalarExpr(E->getArg(0)); 275 Value *V2 = EmitScalarExpr(E->getArg(1)); 276 Value *C = EmitScalarExpr(E->getArg(2)); 277 Function *Callee = 278 CGM.getIntrinsic(Intrinsic::wasm_bitselect, ConvertType(E->getType())); 279 return Builder.CreateCall(Callee, {V1, V2, C}); 280 } 281 case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: { 282 Value *LHS = EmitScalarExpr(E->getArg(0)); 283 Value *RHS = EmitScalarExpr(E->getArg(1)); 284 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot); 285 return Builder.CreateCall(Callee, {LHS, RHS}); 286 } 287 case WebAssembly::BI__builtin_wasm_any_true_v128: 288 case WebAssembly::BI__builtin_wasm_all_true_i8x16: 289 case WebAssembly::BI__builtin_wasm_all_true_i16x8: 290 case WebAssembly::BI__builtin_wasm_all_true_i32x4: 291 case WebAssembly::BI__builtin_wasm_all_true_i64x2: { 292 unsigned IntNo; 293 switch (BuiltinID) { 294 case WebAssembly::BI__builtin_wasm_any_true_v128: 295 IntNo = Intrinsic::wasm_anytrue; 296 break; 297 case WebAssembly::BI__builtin_wasm_all_true_i8x16: 298 case WebAssembly::BI__builtin_wasm_all_true_i16x8: 299 case WebAssembly::BI__builtin_wasm_all_true_i32x4: 300 case WebAssembly::BI__builtin_wasm_all_true_i64x2: 301 IntNo = Intrinsic::wasm_alltrue; 302 break; 303 default: 304 llvm_unreachable("unexpected builtin ID"); 305 } 306 Value *Vec = EmitScalarExpr(E->getArg(0)); 307 Function *Callee = CGM.getIntrinsic(IntNo, Vec->getType()); 308 return Builder.CreateCall(Callee, {Vec}); 309 } 310 case WebAssembly::BI__builtin_wasm_bitmask_i8x16: 311 case WebAssembly::BI__builtin_wasm_bitmask_i16x8: 312 case WebAssembly::BI__builtin_wasm_bitmask_i32x4: 313 case WebAssembly::BI__builtin_wasm_bitmask_i64x2: { 314 Value *Vec = EmitScalarExpr(E->getArg(0)); 315 Function *Callee = 316 CGM.getIntrinsic(Intrinsic::wasm_bitmask, Vec->getType()); 317 return Builder.CreateCall(Callee, {Vec}); 318 } 319 case WebAssembly::BI__builtin_wasm_abs_f16x8: 320 case WebAssembly::BI__builtin_wasm_abs_f32x4: 321 case WebAssembly::BI__builtin_wasm_abs_f64x2: { 322 Value *Vec = EmitScalarExpr(E->getArg(0)); 323 Function *Callee = CGM.getIntrinsic(Intrinsic::fabs, Vec->getType()); 324 return Builder.CreateCall(Callee, {Vec}); 325 } 326 case WebAssembly::BI__builtin_wasm_sqrt_f16x8: 327 case WebAssembly::BI__builtin_wasm_sqrt_f32x4: 328 case WebAssembly::BI__builtin_wasm_sqrt_f64x2: { 329 Value *Vec = EmitScalarExpr(E->getArg(0)); 330 Function *Callee = CGM.getIntrinsic(Intrinsic::sqrt, Vec->getType()); 331 return Builder.CreateCall(Callee, {Vec}); 332 } 333 case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8: 334 case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8: 335 case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4: 336 case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: { 337 Value *Low = EmitScalarExpr(E->getArg(0)); 338 Value *High = EmitScalarExpr(E->getArg(1)); 339 unsigned IntNo; 340 switch (BuiltinID) { 341 case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8: 342 case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4: 343 IntNo = Intrinsic::wasm_narrow_signed; 344 break; 345 case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8: 346 case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: 347 IntNo = Intrinsic::wasm_narrow_unsigned; 348 break; 349 default: 350 llvm_unreachable("unexpected builtin ID"); 351 } 352 Function *Callee = 353 CGM.getIntrinsic(IntNo, {ConvertType(E->getType()), Low->getType()}); 354 return Builder.CreateCall(Callee, {Low, High}); 355 } 356 case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4: 357 case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: { 358 Value *Vec = EmitScalarExpr(E->getArg(0)); 359 unsigned IntNo; 360 switch (BuiltinID) { 361 case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4: 362 IntNo = Intrinsic::fptosi_sat; 363 break; 364 case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: 365 IntNo = Intrinsic::fptoui_sat; 366 break; 367 default: 368 llvm_unreachable("unexpected builtin ID"); 369 } 370 llvm::Type *SrcT = Vec->getType(); 371 llvm::Type *TruncT = SrcT->getWithNewType(Builder.getInt32Ty()); 372 Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT}); 373 Value *Trunc = Builder.CreateCall(Callee, Vec); 374 Value *Splat = Constant::getNullValue(TruncT); 375 return Builder.CreateShuffleVector(Trunc, Splat, {0, 1, 2, 3}); 376 } 377 case WebAssembly::BI__builtin_wasm_shuffle_i8x16: { 378 Value *Ops[18]; 379 size_t OpIdx = 0; 380 Ops[OpIdx++] = EmitScalarExpr(E->getArg(0)); 381 Ops[OpIdx++] = EmitScalarExpr(E->getArg(1)); 382 while (OpIdx < 18) { 383 std::optional<llvm::APSInt> LaneConst = 384 E->getArg(OpIdx)->getIntegerConstantExpr(getContext()); 385 assert(LaneConst && "Constant arg isn't actually constant?"); 386 Ops[OpIdx++] = llvm::ConstantInt::get(getLLVMContext(), *LaneConst); 387 } 388 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_shuffle); 389 return Builder.CreateCall(Callee, Ops); 390 } 391 case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8: 392 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8: 393 case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4: 394 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4: 395 case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2: 396 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: { 397 Value *A = EmitScalarExpr(E->getArg(0)); 398 Value *B = EmitScalarExpr(E->getArg(1)); 399 Value *C = EmitScalarExpr(E->getArg(2)); 400 unsigned IntNo; 401 switch (BuiltinID) { 402 case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8: 403 case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4: 404 case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2: 405 IntNo = Intrinsic::wasm_relaxed_madd; 406 break; 407 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8: 408 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4: 409 case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: 410 IntNo = Intrinsic::wasm_relaxed_nmadd; 411 break; 412 default: 413 llvm_unreachable("unexpected builtin ID"); 414 } 415 Function *Callee = CGM.getIntrinsic(IntNo, A->getType()); 416 return Builder.CreateCall(Callee, {A, B, C}); 417 } 418 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i8x16: 419 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i16x8: 420 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i32x4: 421 case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i64x2: { 422 Value *A = EmitScalarExpr(E->getArg(0)); 423 Value *B = EmitScalarExpr(E->getArg(1)); 424 Value *C = EmitScalarExpr(E->getArg(2)); 425 Function *Callee = 426 CGM.getIntrinsic(Intrinsic::wasm_relaxed_laneselect, A->getType()); 427 return Builder.CreateCall(Callee, {A, B, C}); 428 } 429 case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: { 430 Value *Src = EmitScalarExpr(E->getArg(0)); 431 Value *Indices = EmitScalarExpr(E->getArg(1)); 432 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_swizzle); 433 return Builder.CreateCall(Callee, {Src, Indices}); 434 } 435 case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: 436 case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: 437 case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: 438 case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: { 439 Value *LHS = EmitScalarExpr(E->getArg(0)); 440 Value *RHS = EmitScalarExpr(E->getArg(1)); 441 unsigned IntNo; 442 switch (BuiltinID) { 443 case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: 444 case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: 445 IntNo = Intrinsic::wasm_relaxed_min; 446 break; 447 case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: 448 case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: 449 IntNo = Intrinsic::wasm_relaxed_max; 450 break; 451 default: 452 llvm_unreachable("unexpected builtin ID"); 453 } 454 Function *Callee = CGM.getIntrinsic(IntNo, LHS->getType()); 455 return Builder.CreateCall(Callee, {LHS, RHS}); 456 } 457 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: 458 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: 459 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2: 460 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: { 461 Value *Vec = EmitScalarExpr(E->getArg(0)); 462 unsigned IntNo; 463 switch (BuiltinID) { 464 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: 465 IntNo = Intrinsic::wasm_relaxed_trunc_signed; 466 break; 467 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: 468 IntNo = Intrinsic::wasm_relaxed_trunc_unsigned; 469 break; 470 case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2: 471 IntNo = Intrinsic::wasm_relaxed_trunc_signed_zero; 472 break; 473 case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: 474 IntNo = Intrinsic::wasm_relaxed_trunc_unsigned_zero; 475 break; 476 default: 477 llvm_unreachable("unexpected builtin ID"); 478 } 479 Function *Callee = CGM.getIntrinsic(IntNo); 480 return Builder.CreateCall(Callee, {Vec}); 481 } 482 case WebAssembly::BI__builtin_wasm_relaxed_q15mulr_s_i16x8: { 483 Value *LHS = EmitScalarExpr(E->getArg(0)); 484 Value *RHS = EmitScalarExpr(E->getArg(1)); 485 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_q15mulr_signed); 486 return Builder.CreateCall(Callee, {LHS, RHS}); 487 } 488 case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8: { 489 Value *LHS = EmitScalarExpr(E->getArg(0)); 490 Value *RHS = EmitScalarExpr(E->getArg(1)); 491 Function *Callee = 492 CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed); 493 return Builder.CreateCall(Callee, {LHS, RHS}); 494 } 495 case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4: { 496 Value *LHS = EmitScalarExpr(E->getArg(0)); 497 Value *RHS = EmitScalarExpr(E->getArg(1)); 498 Value *Acc = EmitScalarExpr(E->getArg(2)); 499 Function *Callee = 500 CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed); 501 return Builder.CreateCall(Callee, {LHS, RHS, Acc}); 502 } 503 case WebAssembly::BI__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4: { 504 Value *LHS = EmitScalarExpr(E->getArg(0)); 505 Value *RHS = EmitScalarExpr(E->getArg(1)); 506 Value *Acc = EmitScalarExpr(E->getArg(2)); 507 Function *Callee = 508 CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32); 509 return Builder.CreateCall(Callee, {LHS, RHS, Acc}); 510 } 511 case WebAssembly::BI__builtin_wasm_loadf16_f32: { 512 Value *Addr = EmitScalarExpr(E->getArg(0)); 513 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_loadf16_f32); 514 return Builder.CreateCall(Callee, {Addr}); 515 } 516 case WebAssembly::BI__builtin_wasm_storef16_f32: { 517 Value *Val = EmitScalarExpr(E->getArg(0)); 518 Value *Addr = EmitScalarExpr(E->getArg(1)); 519 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32); 520 return Builder.CreateCall(Callee, {Val, Addr}); 521 } 522 case WebAssembly::BI__builtin_wasm_splat_f16x8: { 523 Value *Val = EmitScalarExpr(E->getArg(0)); 524 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_splat_f16x8); 525 return Builder.CreateCall(Callee, {Val}); 526 } 527 case WebAssembly::BI__builtin_wasm_extract_lane_f16x8: { 528 Value *Vector = EmitScalarExpr(E->getArg(0)); 529 Value *Index = EmitScalarExpr(E->getArg(1)); 530 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_extract_lane_f16x8); 531 return Builder.CreateCall(Callee, {Vector, Index}); 532 } 533 case WebAssembly::BI__builtin_wasm_replace_lane_f16x8: { 534 Value *Vector = EmitScalarExpr(E->getArg(0)); 535 Value *Index = EmitScalarExpr(E->getArg(1)); 536 Value *Val = EmitScalarExpr(E->getArg(2)); 537 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_replace_lane_f16x8); 538 return Builder.CreateCall(Callee, {Vector, Index, Val}); 539 } 540 case WebAssembly::BI__builtin_wasm_table_get: { 541 assert(E->getArg(0)->getType()->isArrayType()); 542 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); 543 Value *Index = EmitScalarExpr(E->getArg(1)); 544 Function *Callee; 545 if (E->getType().isWebAssemblyExternrefType()) 546 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_externref); 547 else if (E->getType().isWebAssemblyFuncrefType()) 548 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_funcref); 549 else 550 llvm_unreachable( 551 "Unexpected reference type for __builtin_wasm_table_get"); 552 return Builder.CreateCall(Callee, {Table, Index}); 553 } 554 case WebAssembly::BI__builtin_wasm_table_set: { 555 assert(E->getArg(0)->getType()->isArrayType()); 556 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); 557 Value *Index = EmitScalarExpr(E->getArg(1)); 558 Value *Val = EmitScalarExpr(E->getArg(2)); 559 Function *Callee; 560 if (E->getArg(2)->getType().isWebAssemblyExternrefType()) 561 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_externref); 562 else if (E->getArg(2)->getType().isWebAssemblyFuncrefType()) 563 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_funcref); 564 else 565 llvm_unreachable( 566 "Unexpected reference type for __builtin_wasm_table_set"); 567 return Builder.CreateCall(Callee, {Table, Index, Val}); 568 } 569 case WebAssembly::BI__builtin_wasm_table_size: { 570 assert(E->getArg(0)->getType()->isArrayType()); 571 Value *Value = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); 572 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size); 573 return Builder.CreateCall(Callee, Value); 574 } 575 case WebAssembly::BI__builtin_wasm_table_grow: { 576 assert(E->getArg(0)->getType()->isArrayType()); 577 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); 578 Value *Val = EmitScalarExpr(E->getArg(1)); 579 Value *NElems = EmitScalarExpr(E->getArg(2)); 580 581 Function *Callee; 582 if (E->getArg(1)->getType().isWebAssemblyExternrefType()) 583 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref); 584 else if (E->getArg(2)->getType().isWebAssemblyFuncrefType()) 585 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref); 586 else 587 llvm_unreachable( 588 "Unexpected reference type for __builtin_wasm_table_grow"); 589 590 return Builder.CreateCall(Callee, {Table, Val, NElems}); 591 } 592 case WebAssembly::BI__builtin_wasm_table_fill: { 593 assert(E->getArg(0)->getType()->isArrayType()); 594 Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); 595 Value *Index = EmitScalarExpr(E->getArg(1)); 596 Value *Val = EmitScalarExpr(E->getArg(2)); 597 Value *NElems = EmitScalarExpr(E->getArg(3)); 598 599 Function *Callee; 600 if (E->getArg(2)->getType().isWebAssemblyExternrefType()) 601 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_externref); 602 else if (E->getArg(2)->getType().isWebAssemblyFuncrefType()) 603 Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref); 604 else 605 llvm_unreachable( 606 "Unexpected reference type for __builtin_wasm_table_fill"); 607 608 return Builder.CreateCall(Callee, {Table, Index, Val, NElems}); 609 } 610 case WebAssembly::BI__builtin_wasm_table_copy: { 611 assert(E->getArg(0)->getType()->isArrayType()); 612 Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); 613 Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this); 614 Value *DstIdx = EmitScalarExpr(E->getArg(2)); 615 Value *SrcIdx = EmitScalarExpr(E->getArg(3)); 616 Value *NElems = EmitScalarExpr(E->getArg(4)); 617 618 Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_copy); 619 620 return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems}); 621 } 622 default: 623 return nullptr; 624 } 625 } 626