diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -25,6 +25,10 @@ BUILTIN(__builtin_wasm_memory_size, "zIi", "n") BUILTIN(__builtin_wasm_memory_grow, "zIiz", "n") +// Bulk memory builtins +TARGET_BUILTIN(__builtin_wasm_memory_init, "vIiv*ii", "", "bulk-memory") +TARGET_BUILTIN(__builtin_wasm_data_drop, "vIi", "", "bulk-memory") + // Floating point min/max BUILTIN(__builtin_wasm_min_f32, "fff", "nc") BUILTIN(__builtin_wasm_max_f32, "fff", "nc") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13470,6 +13470,34 @@ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_grow, ResultType); return Builder.CreateCall(Callee, Args); } + case WebAssembly::BI__builtin_wasm_memory_init: { + const Expr *SegArg = E->getArg(0); + llvm::APSInt SegConst; + if (!SegArg->isIntegerConstantExpr(SegConst, getContext())) + llvm_unreachable("Constant arg isn't actually constant?"); + llvm::Type *SegType = ConvertType(SegArg->getType()); + llvm::Type *IdxType = llvm::Type::getInt32Ty(getLLVMContext()); + llvm::Type *DstType = + ConvertType(E->getArg(1)->getType())->getPointerElementType(); + Value *Args[] = {llvm::ConstantInt::get(getLLVMContext(), SegConst), + llvm::ConstantInt::get(getLLVMContext(), + llvm::APSInt(llvm::APInt(32, 0))), + EmitScalarExpr(E->getArg(1)), EmitScalarExpr(E->getArg(2)), + EmitScalarExpr(E->getArg(3))}; + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_init, + {SegType, IdxType, DstType}); + return Builder.CreateCall(Callee, Args); + } + case WebAssembly::BI__builtin_wasm_data_drop: { + const Expr *SegArg = E->getArg(0); + llvm::APSInt SegConst; + if (!SegArg->isIntegerConstantExpr(SegConst, getContext())) + llvm_unreachable("Constant arg isn't actually constant?"); + llvm::Type *SegType = ConvertType(SegArg->getType()); + Value *Arg = llvm::ConstantInt::get(getLLVMContext(), SegConst); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_data_drop, SegType); + return Builder.CreateCall(Callee, {Arg}); + } case WebAssembly::BI__builtin_wasm_throw: { Value *Tag = EmitScalarExpr(E->getArg(0)); Value *Obj = EmitScalarExpr(E->getArg(1)); diff --git a/clang/test/CodeGen/builtins-wasm.c b/clang/test/CodeGen/builtins-wasm.c --- a/clang/test/CodeGen/builtins-wasm.c +++ b/clang/test/CodeGen/builtins-wasm.c @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +unimplemented-simd128 -target-feature +nontrapping-fptoint -target-feature +exception-handling -fno-lax-vector-conversions -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes WEBASSEMBLY,WEBASSEMBLY32 -// RUN: %clang_cc1 -triple wasm64-unknown-unknown -target-feature +unimplemented-simd128 -target-feature +nontrapping-fptoint -target-feature +exception-handling -fno-lax-vector-conversions -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes WEBASSEMBLY,WEBASSEMBLY64 -// RUN: not %clang_cc1 -triple wasm64-unknown-unknown -target-feature +nontrapping-fptoint -target-feature +exception-handling -fno-lax-vector-conversions -O3 -emit-llvm -o - %s 2>&1 | FileCheck %s -check-prefixes MISSING-SIMD +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-feature +unimplemented-simd128 -target-feature +nontrapping-fptoint -target-feature +exception-handling -target-feature +bulk-memory -fno-lax-vector-conversions -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes WEBASSEMBLY,WEBASSEMBLY32 +// RUN: %clang_cc1 -triple wasm64-unknown-unknown -target-feature +unimplemented-simd128 -target-feature +nontrapping-fptoint -target-feature +exception-handling -target-feature +bulk-memory -fno-lax-vector-conversions -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes WEBASSEMBLY,WEBASSEMBLY64 +// RUN: not %clang_cc1 -triple wasm64-unknown-unknown -target-feature +nontrapping-fptoint -target-feature +exception-handling -target-feature +bulk-memory -fno-lax-vector-conversions -O3 -emit-llvm -o - %s 2>&1 | FileCheck %s -check-prefixes MISSING-SIMD // SIMD convenience types typedef char i8x16 __attribute((vector_size(16))); @@ -26,6 +26,18 @@ // WEBASSEMBLY64: call i64 @llvm.wasm.memory.grow.i64(i32 0, i64 %{{.*}}) } +void memory_init(void *dest, int offset, int size) { + __builtin_wasm_memory_init(3, dest, offset, size); + // WEBASSEMBLY32: call void @llvm.wasm.memory.init.i32.i32.i8(i32 3, i32 0, i8* %{{.*}}, i32 %{{.*}}, i32 %{{.*}}) + // WEBASSEMBLY64: call void @llvm.wasm.memory.init.i32.i32.i8(i32 3, i32 0, i8* %{{.*}}, i32 %{{.*}}, i32 %{{.*}}) +} + +void data_drop() { + __builtin_wasm_data_drop(3); + // WEBASSEMBLY32: call void @llvm.wasm.data.drop.i32(i32 3) + // WEBASSEMBLY64: call void @llvm.wasm.data.drop.i32(i32 3) +} + void throw(unsigned int tag, void *obj) { return __builtin_wasm_throw(tag, obj); // WEBASSEMBLY32: call void @llvm.wasm.throw(i32 %{{.*}}, i8* %{{.*}}) diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -110,4 +110,20 @@ [llvm_anyvector_ty], [IntrNoMem, IntrSpeculatable]>; +//===----------------------------------------------------------------------===// +// Bulk memory intrinsics +//===----------------------------------------------------------------------===// + +def int_wasm_memory_init : + Intrinsic<[], + [llvm_anyint_ty, llvm_anyint_ty, LLVMPointerType, + llvm_i32_ty, llvm_i32_ty], + [IntrWriteMem, IntrArgMemOnly, WriteOnly<1>], + "", [SDNPMemOperand]>; +def int_wasm_data_drop : + Intrinsic<[], + [llvm_anyint_ty], + [IntrNoDuplicate, IntrHasSideEffects], + "", [SDNPMemOperand]>; + } // TargetPrefix = "wasm" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrBulkMemory.td @@ -27,6 +27,31 @@ def wasm_memcpy : SDNode<"WebAssemblyISD::MEMORY_COPY", wasm_memcpy_t, [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>; +//===----------------------------------------------------------------------===// +// memory.init +//===----------------------------------------------------------------------===// + +let mayStore = 1 in +defm MEMORY_INIT : + BULK_I<(outs), + (ins i32imm_op:$seg, i32imm_op:$idx, I32:$dest, + I32:$offset, I32:$size), + (outs), (ins i32imm_op:$seg, i32imm_op:$idx), + [(int_wasm_memory_init (i32 imm:$seg), (i32 imm:$idx), I32:$dest, + I32:$offset, I32:$size + )], + "memory.init\t$seg, $idx, $dest, $offset, $size", + "memory.init\t$seg, $idx", 0x08>; + +//===----------------------------------------------------------------------===// +// data.drop +//===----------------------------------------------------------------------===// + +defm DATA_DROP : + BULK_I<(outs), (ins i32imm_op:$seg), (outs), (ins i32imm_op:$seg), + [(int_wasm_data_drop (i32 imm:$seg))], + "data.drop\t$seg", "data.drop\t$seg", 0x09>; + //===----------------------------------------------------------------------===// // memory.copy //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/WebAssembly/bulk-memory-intrinsics.ll b/llvm/test/CodeGen/WebAssembly/bulk-memory-intrinsics.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/bulk-memory-intrinsics.ll @@ -0,0 +1,28 @@ +; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+bulk-memory | FileCheck %s + +; Test that bulk memory intrinsics lower correctly + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; CHECK-LABEL: memory_init: +; CHECK-NEXT: .functype memory_init (i32, i32, i32) -> () +; CHECK-NEXT: memory.init 0, 3, $0, $1, $2 +; CHECK-NEXT: return +declare void @llvm.wasm.memory.init.i32.i32.i8(i32, i32, i8*, i32, i32) +define void @memory_init(i8* %dest, i32 %offset, i32 %size) { + call void @llvm.wasm.memory.init.i32.i32.i8( + i32 0, i32 3, i8* %dest, i32 %offset, i32 %size + ) + ret void +} + +; CHECK-LABEL: data_drop: +; CHECK-NEXT: .functype data_drop () -> () +; CHECK-NEXT: data.drop 3 +; CHECK-NEXT: return +declare void @llvm.wasm.data.drop.i32(i32) +define void @data_drop() { + call void @llvm.wasm.data.drop.i32(i32 3) + ret void +}