https://github.com/trcrsired updated https://github.com/llvm/llvm-project/pull/162972
>From b2309c93f36530fa497093744e4c984dd05cbee4 Mon Sep 17 00:00:00 2001 From: trcrsired <[email protected]> Date: Sun, 20 Sep 2026 04:03:03 +0800 Subject: [PATCH] [WebAssembly] Memory tagging: squashed mt-2 work onto main Squashed ~140 local commits (WebAssembly stack tagging / memtag intrinsics, clang builtins, and related work) into a single commit on top of llvm-project main. --- .../clang/Basic/BuiltinsWebAssembly.def | 27 ++ .../CodeGen/TargetBuiltins/WebAssembly.cpp | 201 ++++++++++ clang/lib/Driver/SanitizerArgs.cpp | 2 +- clang/lib/Driver/ToolChain.cpp | 2 +- clang/lib/Driver/ToolChains/CommonArgs.cpp | 28 +- .../CodeGen/WebAssembly/builtins-memtag.c | 200 ++++++++++ llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 79 ++++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 13 +- llvm/lib/MC/MCWasmStreamer.cpp | 6 + llvm/lib/Target/WebAssembly/CMakeLists.txt | 2 + llvm/lib/Target/WebAssembly/WebAssembly.h | 5 + llvm/lib/Target/WebAssembly/WebAssembly.td | 4 + .../WebAssembly/WebAssemblyGlobalsTagging.cpp | 141 +++++++ .../WebAssembly/WebAssemblyInstrInfo.td | 4 + .../WebAssembly/WebAssemblyInstrMemtag.td | 233 ++++++++++++ .../WebAssembly/WebAssemblyStackTagging.cpp | 357 ++++++++++++++++++ .../Target/WebAssembly/WebAssemblySubtarget.h | 2 + .../WebAssembly/WebAssemblyTargetMachine.cpp | 5 + .../test/CodeGen/WebAssembly/memtag-addr32.ll | 282 ++++++++++++++ .../test/CodeGen/WebAssembly/memtag-addr64.ll | 282 ++++++++++++++ 20 files changed, 1858 insertions(+), 17 deletions(-) create mode 100644 clang/test/CodeGen/WebAssembly/builtins-memtag.c create mode 100644 llvm/lib/Target/WebAssembly/WebAssemblyGlobalsTagging.cpp create mode 100644 llvm/lib/Target/WebAssembly/WebAssemblyInstrMemtag.td create mode 100644 llvm/lib/Target/WebAssembly/WebAssemblyStackTagging.cpp create mode 100644 llvm/test/CodeGen/WebAssembly/memtag-addr32.ll create mode 100644 llvm/test/CodeGen/WebAssembly/memtag-addr64.ll diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def index a221f771820eb..dcd418f7ddee0 100644 --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -25,6 +25,33 @@ BUILTIN(__builtin_wasm_memory_size, "zIi", "n") BUILTIN(__builtin_wasm_memory_grow, "zIiz", "n") +// Memory Tagging +BUILTIN(__builtin_wasm_memtag_status, "zIi", "n") +BUILTIN(__builtin_wasm_memtag_tagbits, "zIi", "n") +BUILTIN(__builtin_wasm_memtag_startbit, "zIi", "n") +BUILTIN(__builtin_wasm_memtag_extract, "zIiv*", "n") +BUILTIN(__builtin_wasm_memtag_insert, "v*Iiv*z", "n") +BUILTIN(__builtin_wasm_memtag_copy, "v*Iiv*v*", "n") +BUILTIN(__builtin_wasm_memtag_sub, "YIiv*v*", "n") +BUILTIN(__builtin_wasm_memtag_load, "v*Iiv*", "n") +BUILTIN(__builtin_wasm_memtag_store, "vIiv*z", "n") +BUILTIN(__builtin_wasm_memtag_storez, "vIiv*z", "n") +BUILTIN(__builtin_wasm_memtag_untag, "v*Iiv*", "n") +BUILTIN(__builtin_wasm_memtag_untagstore, "v*Iiv*z", "n") +BUILTIN(__builtin_wasm_memtag_untagstorez, "v*Iiv*z", "n") +BUILTIN(__builtin_wasm_memtag_random, "v*Iiv*", "n") +BUILTIN(__builtin_wasm_memtag_randomstore, "v*Iiv*z", "n") +BUILTIN(__builtin_wasm_memtag_randomstorez, "v*Iiv*z", "n") +BUILTIN(__builtin_wasm_memtag_randommask, "v*Iiv*z", "n") +BUILTIN(__builtin_wasm_memtag_randommaskstore, "v*Iiv*zz", "n") +BUILTIN(__builtin_wasm_memtag_randommaskstorez, "v*Iiv*zz", "n") +BUILTIN(__builtin_wasm_memtag_add, "v*Iiv*zz", "n") +BUILTIN(__builtin_wasm_memtag_addstore, "v*Iiv*zzz", "n") +BUILTIN(__builtin_wasm_memtag_addstorez, "v*Iiv*zzz", "n") +BUILTIN(__builtin_wasm_memtag_hint, "v*Iiv*v*z", "n") +BUILTIN(__builtin_wasm_memtag_hintstore, "v*Iiv*zv*z", "n") +BUILTIN(__builtin_wasm_memtag_hintstorez, "v*Iiv*zv*z", "n") + // Bulk memory builtins TARGET_BUILTIN(__builtin_wasm_memory_copy, "vIiIiv*vC*z", "n", "bulk-memory") TARGET_BUILTIN(__builtin_wasm_memory_fill, "vIiv*iz", "n", "bulk-memory") diff --git a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp index 9ecfc10430266..98048e2ee765a 100644 --- a/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp @@ -689,6 +689,207 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems}); } + case WebAssembly::BI__builtin_wasm_memtag_status: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_status, + {ConvertType(E->getType())}); + return Builder.CreateCall(Callee, {Index}); + } + case WebAssembly::BI__builtin_wasm_memtag_tagbits: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_tagbits, + {ConvertType(E->getType())}); + return Builder.CreateCall(Callee, {Index}); + } + case WebAssembly::BI__builtin_wasm_memtag_startbit: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_startbit, + {ConvertType(E->getType())}); + return Builder.CreateCall(Callee, {Index}); + } + case WebAssembly::BI__builtin_wasm_memtag_extract: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_extract, + {ConvertType(E->getType())}); + return Builder.CreateCall(Callee, {Index, Ptr}); + } + case WebAssembly::BI__builtin_wasm_memtag_insert: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *Newtag = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_insert, {Newtag->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, Newtag}); + } + case WebAssembly::BI__builtin_wasm_memtag_copy: { + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_copy); + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr0 = EmitScalarExpr(E->getArg(1)); + Value *Ptr1 = EmitScalarExpr(E->getArg(2)); + return Builder.CreateCall(Callee, {Index, Ptr0, Ptr1}); + } + case WebAssembly::BI__builtin_wasm_memtag_sub: { + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_sub, ConvertType(E->getType())); + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr0 = EmitScalarExpr(E->getArg(1)); + Value *Ptr1 = EmitScalarExpr(E->getArg(2)); + return Builder.CreateCall(Callee, {Index, Ptr0, Ptr1}); + } + case WebAssembly::BI__builtin_wasm_memtag_load: { + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_load); + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + return Builder.CreateCall(Callee, {Index, Ptr}); + } + case WebAssembly::BI__builtin_wasm_memtag_store: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_store, B16->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, B16}); + } + case WebAssembly::BI__builtin_wasm_memtag_storez: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_storez, B16->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, B16}); + } + case WebAssembly::BI__builtin_wasm_memtag_untag: { + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_untag); + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + return Builder.CreateCall(Callee, {Index, Ptr}); + } + case WebAssembly::BI__builtin_wasm_memtag_untagstore: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_untagstore, B16->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, B16}); + } + case WebAssembly::BI__builtin_wasm_memtag_untagstorez: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_untagstorez, B16->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, B16}); + } + case WebAssembly::BI__builtin_wasm_memtag_random: { + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_random); + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + return Builder.CreateCall(Callee, {Index, Ptr}); + } + case WebAssembly::BI__builtin_wasm_memtag_randomstore: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_randomstore, B16->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, B16}); + } + case WebAssembly::BI__builtin_wasm_memtag_randomstorez: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_randomstorez, B16->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, B16}); + } + case WebAssembly::BI__builtin_wasm_memtag_randommask: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *Mask = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_randommask, Mask->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, Mask}); + } + case WebAssembly::BI__builtin_wasm_memtag_randommaskstore: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Value *Mask = EmitScalarExpr(E->getArg(3)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_randommaskstore, + {B16->getType(), Mask->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, B16, Mask}); + } + case WebAssembly::BI__builtin_wasm_memtag_randommaskstorez: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Value *Mask = EmitScalarExpr(E->getArg(3)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_randommaskstorez, + {B16->getType(), Mask->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, B16, Mask}); + } + case WebAssembly::BI__builtin_wasm_memtag_add: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *PtrOffset = EmitScalarExpr(E->getArg(2)); + Value *TagOffset = EmitScalarExpr(E->getArg(3)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_add, + {PtrOffset->getType(), TagOffset->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, PtrOffset, TagOffset}); + } + case WebAssembly::BI__builtin_wasm_memtag_addstore: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Value *PtrOffset = EmitScalarExpr(E->getArg(3)); + Value *TagOffset = EmitScalarExpr(E->getArg(4)); + Function *Callee = CGM.getIntrinsic( + Intrinsic::wasm_memtag_addstore, + {B16->getType(), PtrOffset->getType(), TagOffset->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, B16, PtrOffset, TagOffset}); + } + case WebAssembly::BI__builtin_wasm_memtag_addstorez: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Value *PtrOffset = EmitScalarExpr(E->getArg(3)); + Value *TagOffset = EmitScalarExpr(E->getArg(4)); + Function *Callee = CGM.getIntrinsic( + Intrinsic::wasm_memtag_addstorez, + {B16->getType(), PtrOffset->getType(), TagOffset->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, B16, PtrOffset, TagOffset}); + } + case WebAssembly::BI__builtin_wasm_memtag_hint: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *HintPtr = EmitScalarExpr(E->getArg(2)); + Value *HintIdx = EmitScalarExpr(E->getArg(3)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_memtag_hint, HintIdx->getType()); + return Builder.CreateCall(Callee, {Index, Ptr, HintPtr, HintIdx}); + } + case WebAssembly::BI__builtin_wasm_memtag_hintstore: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Value *HintPtr = EmitScalarExpr(E->getArg(3)); + Value *HintIdx = EmitScalarExpr(E->getArg(4)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_hintstore, + {B16->getType(), HintIdx->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, B16, HintPtr, HintIdx}); + } + case WebAssembly::BI__builtin_wasm_memtag_hintstorez: { + Value *Index = EmitScalarExpr(E->getArg(0)); + Value *Ptr = EmitScalarExpr(E->getArg(1)); + Value *B16 = EmitScalarExpr(E->getArg(2)); + Value *HintPtr = EmitScalarExpr(E->getArg(3)); + Value *HintIdx = EmitScalarExpr(E->getArg(4)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memtag_hintstorez, + {B16->getType(), HintIdx->getType()}); + return Builder.CreateCall(Callee, {Index, Ptr, B16, HintPtr, HintIdx}); + } default: return nullptr; } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 778cde8285aaf..6289b399ab008 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1754,7 +1754,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, << "-fvisibility="; } - if (Sanitizers.has(SanitizerKind::MemtagStack) && + if (Sanitizers.has(SanitizerKind::MemtagStack) && !TC.getTriple().isWasm() && !hasTargetFeatureMTE(CmdArgs)) TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature); } diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 255a9c9602b54..b853350ebe7f4 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1928,7 +1928,7 @@ ToolChain::getSupportedSanitizers(BoundArch BA, if (getTriple().getArch() == llvm::Triple::x86_64 || getTriple().isAArch64(64) || getTriple().isRISCV()) Res |= SanitizerKind::ShadowCallStack; - if (getTriple().isAArch64(64)) + if (getTriple().isAArch64(64) || getTriple().isWasm()) Res |= SanitizerKind::MemTag; if (getTriple().isBPF()) Res |= SanitizerKind::KernelAddress; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index b07438542aae3..b932a2efd3d8d 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1905,22 +1905,24 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); if (SanArgs.hasMemTag()) { - CmdArgs.push_back("-z"); - CmdArgs.push_back( - Args.MakeArgString("memtag-mode=" + SanArgs.getMemtagMode())); - - if (SanArgs.hasMemtagHeap()) { + if (!TC.getTriple().isWasm()) { CmdArgs.push_back("-z"); - CmdArgs.push_back("memtag-heap"); - } + CmdArgs.push_back( + Args.MakeArgString("memtag-mode=" + SanArgs.getMemtagMode())); - if (SanArgs.hasMemtagStack()) { - CmdArgs.push_back("-z"); - CmdArgs.push_back("memtag-stack"); - } + if (SanArgs.hasMemtagHeap()) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("memtag-heap"); + } - if (TC.getTriple().isAndroid()) - CmdArgs.push_back("--android-memtag-note"); + if (SanArgs.hasMemtagStack()) { + CmdArgs.push_back("-z"); + CmdArgs.push_back("memtag-stack"); + } + + if (TC.getTriple().isAndroid()) + CmdArgs.push_back("--android-memtag-note"); + } } return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty() || diff --git a/clang/test/CodeGen/WebAssembly/builtins-memtag.c b/clang/test/CodeGen/WebAssembly/builtins-memtag.c new file mode 100644 index 0000000000000..83db7526e347c --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/builtins-memtag.c @@ -0,0 +1,200 @@ +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,W32 +// RUN: %clang_cc1 -triple wasm64-unknown-unknown -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,W64 + +typedef __SIZE_TYPE__ size_t; + +// --- 0xfc20: memtag.status --- +// CHECK-LABEL: define {{.*}} @test_status() +// W32: call i32 @llvm.wasm.memtag.status.i32(i32 0) +// W64: call i64 @llvm.wasm.memtag.status.i64(i32 0) +size_t test_status() { + return __builtin_wasm_memtag_status(0); +} + +// --- 0xfc21: memtag.extract --- +// CHECK-LABEL: define {{.*}} @test_extract(ptr {{.*}}) +// W32: call i32 @llvm.wasm.memtag.extract.i32(i32 0, ptr {{.*}}) +// W64: call i64 @llvm.wasm.memtag.extract.i64(i32 0, ptr {{.*}}) +size_t test_extract(void *p) { + return __builtin_wasm_memtag_extract(0, p); +} + +// --- 0xfc22: memtag.insert --- +// CHECK-LABEL: define {{.*}} @test_insert(ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.insert.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.insert.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void *test_insert(void *p, size_t v) { + return __builtin_wasm_memtag_insert(0, p, v); +} + +// --- 0xfc23: memtag.tagbits --- +// CHECK-LABEL: define {{.*}} @memtag_tagbits() +// W32: call i32 @llvm.wasm.memtag.tagbits.i32(i32 0) +// W64: call i64 @llvm.wasm.memtag.tagbits.i64(i32 0) +size_t memtag_tagbits() { + return __builtin_wasm_memtag_tagbits(0); +} + +// --- 0xfc24: memtag.startbit --- +// CHECK-LABEL: define {{.*}} @memtag_startbit() +// W32: call i32 @llvm.wasm.memtag.startbit.i32(i32 0) +// W64: call i64 @llvm.wasm.memtag.startbit.i64(i32 0) +size_t memtag_startbit() { + return __builtin_wasm_memtag_startbit(0); +} + +// --- 0xfc25: memtag.copy --- +// CHECK-LABEL: define {{.*}} @memtag_copy(ptr {{.*}}, ptr {{.*}}) +// CHECK: call ptr @llvm.wasm.memtag.copy(i32 0, ptr {{.*}}, ptr {{.*}}) +void *memtag_copy(void *d, void *s) { + return __builtin_wasm_memtag_copy(0, d, s); +} + +// --- 0xfc26: memtag.sub --- +// CHECK-LABEL: define {{.*}} @memtag_sub(ptr {{.*}}, ptr {{.*}}) +// W32: call i32 @llvm.wasm.memtag.sub.i32(i32 0, ptr {{.*}}, ptr {{.*}}) +// W64: call i64 @llvm.wasm.memtag.sub.i64(i32 0, ptr {{.*}}, ptr {{.*}}) +size_t memtag_sub(void *a, void *b) { + return __builtin_wasm_memtag_sub(0, a, b); +} + +// --- 0xfc27: memtag.load --- +// CHECK-LABEL: define {{.*}} @memtag_load(ptr {{.*}}) +// CHECK: call ptr @llvm.wasm.memtag.load(i32 0, ptr {{.*}}) +void *memtag_load(void *p) { + return __builtin_wasm_memtag_load(0, p); +} + +// --- 0xfc28: memtag.untag --- +// CHECK-LABEL: define {{.*}} @memtag_untag(ptr {{.*}}) +// CHECK: call ptr @llvm.wasm.memtag.untag(i32 0, ptr {{.*}}) +void *memtag_untag(void *p) { + return __builtin_wasm_memtag_untag(0, p); +} + +// --- 0xfc29: memtag.untagstore --- +// CHECK-LABEL: define {{.*}} @memtag_untagstore(ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.untagstore.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.untagstore.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void *memtag_untagstore(void *p, size_t v) { + return __builtin_wasm_memtag_untagstore(0, p, v); +} + +// --- 0xfc2a: memtag.untagstorez --- +// CHECK-LABEL: define {{.*}} @memtag_untagstorez(ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.untagstorez.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.untagstorez.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void *memtag_untagstorez(void *p, size_t v) { + return __builtin_wasm_memtag_untagstorez(0, p, v); +} + +// --- 0xfc2b: memtag.store --- +// CHECK-LABEL: define {{.*}} @memtag_store(ptr {{.*}}, {{.*}}) +// W32: call void @llvm.wasm.memtag.store.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call void @llvm.wasm.memtag.store.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void memtag_store(void *p, size_t v) { + __builtin_wasm_memtag_store(0, p, v); +} + +// --- 0xfc2c: memtag.storez --- +// CHECK-LABEL: define {{.*}} @memtag_storez(ptr {{.*}}, {{.*}}) +// W32: call void @llvm.wasm.memtag.storez.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call void @llvm.wasm.memtag.storez.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void memtag_storez(void *p, size_t v) { + __builtin_wasm_memtag_storez(0, p, v); +} + +// --- 0xfc2d: memtag.random --- +// CHECK-LABEL: define {{.*}} @memtag_random(ptr {{.*}}) +// CHECK: call ptr @llvm.wasm.memtag.random(i32 0, ptr {{.*}}) +void *memtag_random(void *p) { + return __builtin_wasm_memtag_random(0, p); +} + +// --- 0xfc2e: memtag.randomstore --- +// CHECK-LABEL: define {{.*}} @memtag_randomstore(ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.randomstore.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.randomstore.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void *memtag_randomstore(void *p, size_t v) { + return __builtin_wasm_memtag_randomstore(0, p, v); +} + +// --- 0xfc2f: memtag.randomstorez --- +// CHECK-LABEL: define {{.*}} @memtag_randomstorez(ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.randomstorez.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.randomstorez.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void *memtag_randomstorez(void *p, size_t v) { + return __builtin_wasm_memtag_randomstorez(0, p, v); +} + +// --- 0xfc30: memtag.randommask --- +// CHECK-LABEL: define {{.*}} @memtag_randommask(ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.randommask.i32(i32 0, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.randommask.i64(i32 0, ptr {{.*}}, i64 {{.*}}) +void *memtag_randommask(void *p, size_t m) { + return __builtin_wasm_memtag_randommask(0, p, m); +} + +// --- 0xfc31: memtag.randommaskstore --- +// CHECK-LABEL: define {{.*}} @memtag_randommaskstore(ptr {{.*}}, {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.randommaskstore.i32.i32(i32 0, ptr {{.*}}, i32 {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.randommaskstore.i64.i64(i32 0, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}) +void *memtag_randommaskstore(void *p, size_t v, size_t m) { + return __builtin_wasm_memtag_randommaskstore(0, p, v, m); +} + +// --- 0xfc32: memtag.randommaskstorez --- +// CHECK-LABEL: define {{.*}} @memtag_randommaskstorez(ptr {{.*}}, {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.randommaskstorez.i32.i32(i32 0, ptr {{.*}}, i32 {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.randommaskstorez.i64.i64(i32 0, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}) +void *memtag_randommaskstorez(void *p, size_t v, size_t m) { + return __builtin_wasm_memtag_randommaskstorez(0, p, v, m); +} + +// --- 0xfc33: memtag.add --- +// CHECK-LABEL: define {{.*}} @memtag_add(ptr {{.*}}, {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.add.i32.i32(i32 0, ptr {{.*}}, i32 {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.add.i64.i64(i32 0, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}) +void *memtag_add(void *p, size_t o, size_t t) { + return __builtin_wasm_memtag_add(0, p, o, t); +} + +// --- 0xfc34: memtag.addstore --- +// CHECK-LABEL: define {{.*}} @memtag_addstore(ptr {{.*}}, {{.*}}, {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.addstore.i32.i32.i32(i32 0, ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.addstore.i64.i64.i64(i32 0, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}, i64 {{.*}}) +void *memtag_addstore(void *p, size_t v, size_t o, size_t t) { + return __builtin_wasm_memtag_addstore(0, p, v, o, t); +} + +// --- 0xfc35: memtag.addstorez --- +// CHECK-LABEL: define {{.*}} @memtag_addstorez(ptr {{.*}}, {{.*}}, {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.addstorez.i32.i32.i32(i32 0, ptr {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.addstorez.i64.i64.i64(i32 0, ptr {{.*}}, i64 {{.*}}, i64 {{.*}}, i64 {{.*}}) +void *memtag_addstorez(void *p, size_t v, size_t o, size_t t) { + return __builtin_wasm_memtag_addstorez(0, p, v, o, t); +} + +// --- 0xfc36: memtag.hint --- +// CHECK-LABEL: define {{.*}} @memtag_hint(ptr {{.*}}, ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.hint.i32(i32 0, ptr {{.*}}, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.hint.i64(i32 0, ptr {{.*}}, ptr {{.*}}, i64 {{.*}}) +void *memtag_hint(void *p, void *h, size_t i) { + return __builtin_wasm_memtag_hint(0, p, h, i); +} + +// --- 0xfc37: memtag.hintstore --- +// CHECK-LABEL: define {{.*}} @memtag_hintstore(ptr {{.*}}, {{.*}}, ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.hintstore.i32.i32(i32 0, ptr {{.*}}, i32 {{.*}}, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.hintstore.i64.i64(i32 0, ptr {{.*}}, i64 {{.*}}, ptr {{.*}}, i64 {{.*}}) +void *memtag_hintstore(void *p, size_t v, void *h, size_t i) { + return __builtin_wasm_memtag_hintstore(0, p, v, h, i); +} + +// --- 0xfc38: memtag.hintstorez --- +// CHECK-LABEL: define {{.*}} @memtag_hintstorez(ptr {{.*}}, {{.*}}, ptr {{.*}}, {{.*}}) +// W32: call ptr @llvm.wasm.memtag.hintstorez.i32.i32(i32 0, ptr {{.*}}, i32 {{.*}}, ptr {{.*}}, i32 {{.*}}) +// W64: call ptr @llvm.wasm.memtag.hintstorez.i64.i64(i32 0, ptr {{.*}}, i64 {{.*}}, ptr {{.*}}, i64 {{.*}}) +void *memtag_hintstorez(void *p, size_t v, void *h, size_t i) { + return __builtin_wasm_memtag_hintstorez(0, p, v, h, i); +} diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td index fbd4b35514ebf..903d58f350a49 100644 --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -415,4 +415,83 @@ def int_wasm_tls_base : [], [IntrReadMem]>; +//===----------------------------------------------------------------------===// +// Memory Tagging intrinsics +//===----------------------------------------------------------------------===// + +def int_wasm_memtag_status : + DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_i32_ty], [IntrNoMem]>; + +def int_wasm_memtag_tagbits : + DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_i32_ty], [IntrNoMem]>; + +def int_wasm_memtag_startbit : + DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_i32_ty], [IntrNoMem]>; + +def int_wasm_memtag_extract : + DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_i32_ty, llvm_ptr_ty], [IntrNoMem]>; + +def int_wasm_memtag_insert : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrNoMem]>; + +def int_wasm_memtag_copy : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty], [IntrNoMem]>; + +def int_wasm_memtag_sub : + DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty], [IntrNoMem]>; + +def int_wasm_memtag_load : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty], [IntrReadMem]>; + +def int_wasm_memtag_untag : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty], [IntrNoMem]>; + +def int_wasm_memtag_untagstore : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrWriteMem]>; + +def int_wasm_memtag_untagstorez : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrWriteMem]>; + +def int_wasm_memtag_store : + DefaultAttrsIntrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrWriteMem]>; + +def int_wasm_memtag_storez : + DefaultAttrsIntrinsic<[], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrWriteMem]>; + +def int_wasm_memtag_random : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_memtag_randomstore : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrHasSideEffects, IntrWriteMem]>; + +def int_wasm_memtag_randomstorez : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrHasSideEffects, IntrWriteMem]>; + +def int_wasm_memtag_randommask : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_memtag_randommaskstore : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty, llvm_anyint_ty], [IntrHasSideEffects, IntrWriteMem]>; + +def int_wasm_memtag_randommaskstorez : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty, llvm_anyint_ty], [IntrHasSideEffects, IntrWriteMem]>; + +def int_wasm_memtag_add : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty, llvm_anyint_ty], [IntrNoMem]>; + +def int_wasm_memtag_addstore : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty, llvm_anyint_ty, llvm_anyint_ty], [IntrWriteMem]>; + +def int_wasm_memtag_addstorez : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty, llvm_anyint_ty, llvm_anyint_ty], [IntrWriteMem]>; + +def int_wasm_memtag_hint : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrNoMem]>; + +def int_wasm_memtag_hintstore : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrWriteMem]>; + +def int_wasm_memtag_hintstorez : + DefaultAttrsIntrinsic<[llvm_ptr_ty], [llvm_i32_ty, llvm_ptr_ty, llvm_anyint_ty, llvm_ptr_ty, llvm_anyint_ty], [IntrWriteMem]>; + } // TargetPrefix = "wasm" diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 52f8f148f7487..b7878a36ba0bc 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -839,10 +839,19 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV, if (GV->isTagged()) { Triple T = TM.getTargetTriple(); - if (T.getArch() != Triple::aarch64) + auto arch = T.getArch(); + + bool supportMemtagGlobals = false; + + if (T.isWasm() || arch == Triple::aarch64) { + supportMemtagGlobals = true; + } + + if (!supportMemtagGlobals) OutContext.reportError(SMLoc(), "tagged symbols (-fsanitize=memtag-globals) are " - "only supported on AArch64"); + "only supported on AArch64 or WebAssembly"); + OutStreamer->emitSymbolAttribute(EmittedSym, MCSA_Memtag); } diff --git a/llvm/lib/MC/MCWasmStreamer.cpp b/llvm/lib/MC/MCWasmStreamer.cpp index 32f60c2089f5a..c86a034623b04 100644 --- a/llvm/lib/MC/MCWasmStreamer.cpp +++ b/llvm/lib/MC/MCWasmStreamer.cpp @@ -119,6 +119,12 @@ bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { Symbol->setNoStrip(); break; + case MCSA_Memtag: +#if 0 + Symbol->setMemtag(true); +#endif + break; + default: // unrecognized directive llvm_unreachable("unexpected MCSymbolAttr"); diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt index e96ac48aa00cb..ed8ca71fab4cb 100644 --- a/llvm/lib/Target/WebAssembly/CMakeLists.txt +++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt @@ -59,6 +59,7 @@ add_llvm_target(WebAssemblyCodeGen WebAssemblyNullifyDebugValueLists.cpp WebAssemblyOptimizeLiveIntervals.cpp WebAssemblyOptimizeReturned.cpp + WebAssemblyStackTagging.cpp WebAssemblyPeephole.cpp WebAssemblyReduceToAnyAllTrue.cpp WebAssemblyRefTypeMem2Local.cpp @@ -77,6 +78,7 @@ add_llvm_target(WebAssemblyCodeGen WebAssemblyTargetObjectFile.cpp WebAssemblyTargetTransformInfo.cpp WebAssemblyUtilities.cpp + WebAssemblyGlobalsTagging.cpp DEPENDS intrinsics_gen diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h index e6aefc2ba43e9..ed792e33fc64f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -325,6 +325,9 @@ class WebAssemblyMCLowerPrePass ModulePass *createWebAssemblyMCLowerPreLegacyPass(); +FunctionPass *createWebAssemblyStackTaggingPass(); +ModulePass *createWebAssemblyGlobalsTaggingPass(); + // PassRegistry initialization declarations. void initializeWebAssemblyOptimizeReturnedLegacyPass(PassRegistry &); void initializeWebAssemblyRefTypeMem2LocalLegacyPass(PassRegistry &); @@ -358,6 +361,8 @@ void initializeWebAssemblyReplacePhysRegsLegacyPass(PassRegistry &); void initializeWebAssemblySetP2AlignOperandsLegacyPass(PassRegistry &); void initializeWebAssemblyCoalesceFeaturesAndStripAtomicsLegacyPass( PassRegistry &); +void initializeWebAssemblyStackTaggingPass(PassRegistry &); +void initializeWebAssemblyGlobalsTaggingPass(PassRegistry &); namespace WebAssembly { enum TargetIndex { diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.td b/llvm/lib/Target/WebAssembly/WebAssembly.td index 979c3dd716ec4..3cc56d4cb983c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.td +++ b/llvm/lib/Target/WebAssembly/WebAssembly.td @@ -96,6 +96,10 @@ def FeatureTailCall : SubtargetFeature<"tail-call", "HasTailCall", "true", "Enable tail call instructions">; +def FeatureMemtag : + SubtargetFeature<"memtag", "HasMemtag", "true", + "Enable memory tagging">; + def FeatureWideArithmetic : SubtargetFeature<"wide-arithmetic", "HasWideArithmetic", "true", "Enable wide-arithmetic instructions">; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyGlobalsTagging.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyGlobalsTagging.cpp new file mode 100644 index 0000000000000..3a8d0237a5cd4 --- /dev/null +++ b/llvm/lib/Target/WebAssembly/WebAssemblyGlobalsTagging.cpp @@ -0,0 +1,141 @@ +//===- WebAssemblyGlobalsTagging.cpp - Global tagging in IR ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// + +#include "WebAssembly.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" + +#include <algorithm> +#include <set> + +using namespace llvm; + +static const Align kTagGranuleSize = Align(16); + +static bool shouldTagGlobal(GlobalVariable &G) { + if (!G.isTagged()) + return false; + + assert(G.hasSanitizerMetadata() && + "Missing sanitizer metadata, but symbol is apparently tagged."); + GlobalValue::SanitizerMetadata Meta = G.getSanitizerMetadata(); + + // For now, don't instrument constant data, as it'll be in .rodata anyway. It + // may be worth instrumenting these in future to stop them from being used as + // gadgets. + if (G.getName().starts_with("llvm.") || G.isThreadLocal() || G.isConstant()) { + Meta.Memtag = false; + G.setSanitizerMetadata(Meta); + return false; + } + + return true; +} + +// Technically, due to ELF symbol interposition semantics, we can't change the +// alignment or size of symbols. If we increase the alignment or size of a +// symbol, the compiler may make optimisations based on this new alignment or +// size. If the symbol is interposed, this optimisation could lead to +// alignment-related or OOB read/write crashes. +// +// This is handled in the linker. When the linker sees multiple declarations of +// a global variable, and some are tagged, and some are untagged, it resolves it +// to be an untagged definition - but preserves the tag-granule-rounded size and +// tag-granule-alignment. This should prevent these kind of crashes intra-DSO. +// For cross-DSO, it's been a reasonable contract that if you're interposing a +// sanitizer-instrumented global, then the interposer also needs to be +// sanitizer-instrumented. +// +// FIXME: In theory, this can be fixed by splitting the size/alignment of +// globals into two uses: an "output alignment" that's emitted to the ELF file, +// and an "optimisation alignment" that's used for optimisation. Thus, we could +// adjust the output alignment only, and still optimise based on the pessimistic +// pre-tagging size/alignment. +static void tagGlobalDefinition(Module &M, GlobalVariable *G) { + Constant *Initializer = G->getInitializer(); + uint64_t SizeInBytes = + M.getDataLayout().getTypeAllocSize(Initializer->getType()); + + uint64_t NewSize = alignTo(SizeInBytes, kTagGranuleSize); + if (SizeInBytes != NewSize) { + // Pad the initializer out to the next multiple of 16 bytes. + llvm::SmallVector<uint8_t> Init(NewSize - SizeInBytes, 0); + Constant *Padding = ConstantDataArray::get(M.getContext(), Init); + Initializer = ConstantStruct::getAnon({Initializer, Padding}); + auto *NewGV = new GlobalVariable( + M, Initializer->getType(), G->isConstant(), G->getLinkage(), + Initializer, "", G, G->getThreadLocalMode(), G->getAddressSpace()); + NewGV->copyAttributesFrom(G); + NewGV->setComdat(G->getComdat()); + NewGV->copyMetadata(G, 0); + + NewGV->takeName(G); + G->replaceAllUsesWith(NewGV); + G->eraseFromParent(); + G = NewGV; + } + + G->setAlignment(std::max(G->getAlign().valueOrOne(), kTagGranuleSize)); + + // Ensure that tagged globals don't get merged by ICF - as they should have + // different tags at runtime. + G->setUnnamedAddr(GlobalValue::UnnamedAddr::None); +} + +namespace { +class WebAssemblyGlobalsTagging : public ModulePass { +public: + static char ID; + + explicit WebAssemblyGlobalsTagging() : ModulePass(ID) { + initializeWebAssemblyGlobalsTaggingPass(*PassRegistry::getPassRegistry()); + } + + bool runOnModule(Module &M) override; + + StringRef getPassName() const override { + return "WebAssembly Globals Tagging"; + } + +private: + std::set<GlobalVariable *> GlobalsToTag; +}; +} // anonymous namespace + +char WebAssemblyGlobalsTagging::ID = 0; + +bool WebAssemblyGlobalsTagging::runOnModule(Module &M) { + // No mutating the globals in-place, or iterator invalidation occurs. + std::vector<GlobalVariable *> GlobalsToTag; + for (GlobalVariable &G : M.globals()) { + if (G.isDeclaration() || !shouldTagGlobal(G)) + continue; + GlobalsToTag.push_back(&G); + } + for (GlobalVariable *G : GlobalsToTag) { + tagGlobalDefinition(M, G); + } + return true; +} + +INITIALIZE_PASS_BEGIN(WebAssemblyGlobalsTagging, "WebAssembly-globals-tagging", + "WebAssembly Globals Tagging Pass", false, false) +INITIALIZE_PASS_END(WebAssemblyGlobalsTagging, "WebAssembly-globals-tagging", + "WebAssembly Globals Tagging Pass", false, false) + +ModulePass *llvm::createWebAssemblyGlobalsTaggingPass() { + return new WebAssemblyGlobalsTagging(); +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index 7669f301b2c48..c7d557f375930 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -57,6 +57,9 @@ def HasMultiMemory : Predicate<"Subtarget->hasMultiMemory()">, AssemblerPredicate<(all_of FeatureMultiMemory), "multimemory">; +def HasMemtag : + Predicate<"Subtarget->hasMemtag()">, + AssemblerPredicate<(all_of FeatureMemtag), "memtag">; def HasMultivalue : Predicate<"Subtarget->hasMultivalue()">, AssemblerPredicate<(all_of FeatureMultivalue), "multivalue">; @@ -483,3 +486,4 @@ include "WebAssemblyInstrSIMD.td" include "WebAssemblyInstrRef.td" include "WebAssemblyInstrBulkMemory.td" include "WebAssemblyInstrTable.td" +include "WebAssemblyInstrMemtag.td" diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemtag.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemtag.td new file mode 100644 index 0000000000000..ed99c9a3029ed --- /dev/null +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemtag.td @@ -0,0 +1,233 @@ +// WebAssemblyInstrMemtag.td - WebAssembly Memtag codegen support -*- memtaggen -*- +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// WebAssembly Mem Table operand code-gen constructs. +/// Instructions that handle memtags +//===----------------------------------------------------------------------===// + +multiclass MemoryTaggingOps<WebAssemblyRegClass rc, string B> { + +defm MEMTAG_STATUS_A#B: I<(outs rc:$statuscode), (ins i32imm:$tableidx), + (outs), (ins i32imm:$tableidx), + [(set rc:$statuscode, + (int_wasm_memtag_status (i32 imm:$tableidx)))], + "memtag.status\t$statuscode, $tableidx", + "memtag.status\t$tableidx", + 0xfc20>; + +defm MEMTAG_EXTRACT_A#B: I<(outs rc:$taggedval), (ins i32imm:$tableidx, rc:$ptr), + (outs), (ins i32imm:$tableidx), + [(set rc:$taggedval, + (int_wasm_memtag_extract (i32 imm:$tableidx), rc:$ptr))], + "memtag.extract\t$taggedval, $tableidx, $ptr", + "memtag.extract\t$tableidx", + 0xfc21>; + +defm MEMTAG_INSERT_A#B: I<(outs rc:$taggedptr), (ins i32imm:$tableidx, rc:$ptr, rc:$insertval), + (outs), (ins i32imm:$tableidx), + [(set rc:$taggedptr, + (int_wasm_memtag_insert (i32 imm:$tableidx), rc:$ptr, rc:$insertval))], + "memtag.insert\t$taggedptr, $tableidx, $ptr, $insertval", + "memtag.insert\t$tableidx", + 0xfc22>; + +defm MEMTAG_TAGBITS_A#B: I<(outs rc:$taggedbits), (ins i32imm:$tableidx), + (outs), (ins i32imm:$tableidx), + [(set rc:$taggedbits, + (int_wasm_memtag_tagbits (i32 imm:$tableidx)))], + "memtag.tagbits\t$taggedbits, $tableidx", + "memtag.tagbits\t$tableidx", + 0xfc23>; + +defm MEMTAG_STARTBIT_A#B: I<(outs rc:$startbit), (ins i32imm:$tableidx), + (outs), (ins i32imm:$tableidx), + [(set rc:$startbit, + (int_wasm_memtag_startbit (i32 imm:$tableidx)))], + "memtag.startbit\t$startbit, $tableidx", + "memtag.startbit\t$tableidx", + 0xfc24>; + +defm MEMTAG_COPY_A#B: I<(outs rc:$dstwsrctag), (ins i32imm:$tableidx, rc:$dst, rc:$src), + (outs), (ins i32imm:$tableidx), + [(set rc:$dstwsrctag, + (int_wasm_memtag_copy (i32 imm:$tableidx), rc:$dst, rc:$src))], + "memtag.copy\t$dstwsrctag, $tableidx, $dst, $src", + "memtag.copy\t$tableidx", + 0xfc25>; + +defm MEMTAG_SUB_A#B: I<(outs rc:$diff), (ins i32imm:$tableidx, rc:$minuendptr, rc:$subtrahendptr), + (outs), (ins i32imm:$tableidx), + [(set rc:$diff, + (int_wasm_memtag_sub (i32 imm:$tableidx), rc:$minuendptr, rc:$subtrahendptr))], + "memtag.sub\t$diff, $tableidx, $minuendptr, $subtrahendptr", + "memtag.sub\t$tableidx", + 0xfc26>; + +let mayLoad = 1 in +defm MEMTAG_LOAD_A#B: I<(outs rc:$taggedptr), (ins i32imm:$tableidx, rc:$src), + (outs), (ins i32imm:$tableidx), + [(set rc:$taggedptr, + (int_wasm_memtag_load (i32 imm:$tableidx), rc:$src))], + "memtag.load\t$taggedptr, $tableidx, $src", + "memtag.load\t$tableidx", + 0xfc27>; + +defm MEMTAG_UNTAG_A#B: I<(outs rc:$untaggedptr), (ins i32imm:$tableidx, rc:$ptr), + (outs), (ins i32imm:$tableidx), + [(set rc:$untaggedptr, + (int_wasm_memtag_untag (i32 imm:$tableidx), rc:$ptr))], + "memtag.untag\t$untaggedptr, $tableidx, $ptr", + "memtag.untag\t$tableidx", + 0xfc28>; + +let mayStore = 1 in +defm MEMTAG_UNTAGSTORE_A#B: I<(outs rc:$untaggedptr), (ins i32imm:$tableidx, rc:$src, rc:$b16), + (outs), (ins i32imm:$tableidx), + [(set rc:$untaggedptr, + (int_wasm_memtag_untagstore (i32 imm:$tableidx), rc:$src, rc:$b16))], + "memtag.untagstore\t$tableidx, $src, $b16", + "memtag.untagstore\t$tableidx", + 0xfc29>; + +let mayStore = 1 in +defm MEMTAG_UNTAGSTOREZ_A#B: I<(outs rc:$untaggedptr), (ins i32imm:$tableidx, rc:$src, rc:$b16), + (outs), (ins i32imm:$tableidx), + [(set rc:$untaggedptr, + (int_wasm_memtag_untagstorez (i32 imm:$tableidx), rc:$src, rc:$b16))], + "memtag.untagstorez\t$tableidx, $src, $b16", + "memtag.untagstorez\t$tableidx", + 0xfc2a>; + +let mayStore = 1 in +defm MEMTAG_STORE_A#B: I<(outs), (ins i32imm:$tableidx, rc:$src, rc:$b16), + (outs), (ins i32imm:$tableidx), + [(int_wasm_memtag_store (i32 imm:$tableidx), rc:$src, rc:$b16)], + "memtag.store\t$tableidx, $src, $b16", + "memtag.store\t$tableidx", + 0xfc2b>; + +let mayStore = 1 in +defm MEMTAG_STOREZ_A#B: I<(outs), (ins i32imm:$tableidx, rc:$src, rc:$b16), + (outs), (ins i32imm:$tableidx), + [(int_wasm_memtag_storez (i32 imm:$tableidx), rc:$src, rc:$b16)], + "memtag.storez\t$tableidx, $src, $b16", + "memtag.storez\t$tableidx", + 0xfc2c>; + +let hasSideEffects = 1 in +defm MEMTAG_RANDOM_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_random (i32 imm:$tableidx), rc:$src))], + "memtag.random\t$dst, $tableidx, $src", + "memtag.random\t$tableidx", + 0xfc2d>; + +let hasSideEffects = 1, mayStore = 1 in +defm MEMTAG_RANDOMSTORE_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_randomstore (i32 imm:$tableidx), rc:$src, rc:$b16))], + "memtag.randomstore\t$dst, $tableidx, $src, $b16", + "memtag.randomstore\t$tableidx", + 0xfc2e>; + +let hasSideEffects = 1, mayStore = 1 in +defm MEMTAG_RANDOMSTOREZ_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_randomstorez (i32 imm:$tableidx), rc:$src, rc:$b16))], + "memtag.randomstorez\t$dst, $src, $tableidx, $b16", + "memtag.randomstorez\t$tableidx", + 0xfc2f>; + +let hasSideEffects = 1 in +defm MEMTAG_RANDOMMASK_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$mask), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_randommask (i32 imm:$tableidx), rc:$src, rc:$mask))], + "memtag.randommask\t$dst, $tableidx, $src, $mask", + "memtag.randommask\t$tableidx", + 0xfc30>; + + +let hasSideEffects = 1, mayStore = 1 in +defm MEMTAG_RANDOMMASKSTORE_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16, rc:$mask), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_randommaskstore (i32 imm:$tableidx), rc:$src, rc:$b16, rc:$mask))], + "memtag.randommaskstore\t$dst, $tableidx, $src, $b16, $mask", + "memtag.randommaskstore\t$tableidx", + 0xfc31>; + +let hasSideEffects = 1, mayStore = 1 in +defm MEMTAG_RANDOMMASKSTOREZ_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16, rc:$mask), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_randommaskstorez (i32 imm:$tableidx), rc:$src, rc:$b16, rc:$mask))], + "memtag.randommaskstorez\t$dst, $src, $tableidx, $b16, $mask", + "memtag.randommaskstorez\t$tableidx", + 0xfc32>; + +defm MEMTAG_ADD_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$addroffset, rc:$tagoffset), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_add (i32 imm:$tableidx), rc:$src, rc:$addroffset, rc:$tagoffset))], + "memtag.add\t$dst, $tableidx, $src, $addroffset, $tagoffset", + "memtag.add\t$tableidx", + 0xfc33>; + +let mayStore = 1 in +defm MEMTAG_ADDSTORE_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16, rc:$addroffset, rc:$tagoffset), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_addstore (i32 imm:$tableidx), rc:$src, rc:$b16, rc:$addroffset, rc:$tagoffset))], + "memtag.addstore\t$dst, $tableidx, $src, $b16, $addroffset, $tagoffset", + "memtag.addstore\t$tableidx", + 0xfc34>; + +let mayStore = 1 in +defm MEMTAG_ADDSTOREZ_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16, rc:$addroffset, rc:$tagoffset), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_addstorez (i32 imm:$tableidx), rc:$src, rc:$b16, rc:$addroffset, rc:$tagoffset))], + "memtag.addstorez\t$dst, $tableidx, $src, $b16, $addroffset, $tagoffset", + "memtag.addstorez\t$tableidx", + 0xfc35>; + +defm MEMTAG_HINT_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$hintaddr, rc:$index), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_hint (i32 imm:$tableidx), rc:$src, rc:$hintaddr, rc:$index))], + "memtag.hint\t$dst, $tableidx, $src, $hintaddr, $index", + "memtag.hint\t$tableidx", + 0xfc36>; + +let mayStore = 1 in +defm MEMTAG_HINTSTORE_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16, rc:$hintaddr, rc:$index), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_hintstore (i32 imm:$tableidx), rc:$src, rc:$b16, rc:$hintaddr, rc:$index))], + "memtag.hintstore\t$dst, $tableidx, $src, $b16, $hintaddr, $index", + "memtag.hintstore\t$tableidx", + 0xfc37>; + +let mayStore = 1 in +defm MEMTAG_HINTSTOREZ_A#B: I<(outs rc:$dst), (ins i32imm:$tableidx, rc:$src, rc:$b16, rc:$hintaddr, rc:$index), + (outs), (ins i32imm:$tableidx), + [(set rc:$dst, + (int_wasm_memtag_hintstorez (i32 imm:$tableidx), rc:$src, rc:$b16, rc:$hintaddr, rc:$index))], + "memtag.hintstorez\t$dst, $tableidx, $src, $b16, $hintaddr, $index", + "memtag.hintstorez\t$tableidx", + 0xfc38>; + +} + +defm : MemoryTaggingOps<I32, "32">; +defm : MemoryTaggingOps<I64, "64">; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyStackTagging.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyStackTagging.cpp new file mode 100644 index 0000000000000..f6514008a05a3 --- /dev/null +++ b/llvm/lib/Target/WebAssembly/WebAssemblyStackTagging.cpp @@ -0,0 +1,357 @@ +//===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "WebAssembly.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/PostDominators.h" +#include "llvm/Analysis/StackSafetyAnalysis.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/IntrinsicsWebAssembly.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/MemoryTaggingSupport.h" + +using namespace llvm; + +#define DEBUG_TYPE "wasm-stack-tagging" + +namespace { + +struct WebAssemblyStackTagging : public FunctionPass { + static char ID; + StackSafetyGlobalInfo const *SSI = nullptr; + DataLayout const *DL = nullptr; + AAResults *AA = nullptr; + WebAssemblyStackTagging() : FunctionPass(ID) {} + + void untagAlloca(AllocaInst *AI, Instruction *InsertBefore, uint64_t Size, + Function *StoreTagDecl, Type *ArgOp0Type); + + Instruction *insertBaseTaggedPointer( + const MapVector<AllocaInst *, memtag::AllocaInfo> &Allocas, + const DominatorTree *DT); + + bool runOnFunction(Function &) override; + +private: + Function *F = nullptr; +#if 1 + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + AU.addRequired<StackSafetyGlobalInfoWrapperPass>(); +#if 0 + if (MergeInit) + AU.addRequired<AAResultsWrapperPass>(); +#endif + AU.addRequired<OptimizationRemarkEmitterWrapperPass>(); + } +#endif +}; + +inline bool canCombineStore(const memtag::AllocaInfo &Info, AllocaInst *AI, + DominatorTree *DT) { + // Must have exactly one lifetime interval. + if (Info.LifetimeStart.size() != 1 || Info.LifetimeEnd.size() != 1) + return false; + + IntrinsicInst *Start = Info.LifetimeStart.front(); + + // Check dominance and instruction order for every use. + for (User *U : AI->users()) { + auto *I = dyn_cast<Instruction>(U); + if (!I) + continue; + + // Lifetime intrinsics are not rewritten and do not matter. + if (isa<LifetimeIntrinsic>(I)) + continue; + + // If Start does not dominate the use, combined tagging is unsafe. + if (!DT->dominates(Start, I)) + return false; + + // If in the same block, Start must come before the use. + if (Start->getParent() == I->getParent() && !Start->comesBefore(I)) + return false; + } + + return true; +} + +static const inline Align kTagGranuleSize = Align(16); + +} // namespace + +void WebAssemblyStackTagging::untagAlloca(AllocaInst *AI, + Instruction *InsertBefore, + uint64_t Size, Function *StoreTagDecl, + Type *ArgOp0Type) { + + IRBuilder<> IRB(InsertBefore); + IRB.CreateCall(StoreTagDecl, + {IRB.getInt32(0), AI, ConstantInt::get(ArgOp0Type, Size)}); +} + +Instruction *WebAssemblyStackTagging::insertBaseTaggedPointer( + const MapVector<AllocaInst *, memtag::AllocaInfo> &AllocasToInstrument, + const DominatorTree *DT) { + BasicBlock *PrologueBB = nullptr; + // Try sinking IRG as deep as possible to avoid hurting shrink wrap. + for (auto &I : AllocasToInstrument) { + const memtag::AllocaInfo &Info = I.second; + AllocaInst *AI = Info.AI; + if (!PrologueBB) { + PrologueBB = AI->getParent(); + continue; + } + PrologueBB = DT->findNearestCommonDominator(PrologueBB, AI->getParent()); + } + assert(PrologueBB); + + IRBuilder<> IRB(&PrologueBB->front()); + Function *RdTag = Intrinsic::getOrInsertDeclaration( + F->getParent(), Intrinsic::wasm_memtag_random); + Instruction *Base = + IRB.CreateCall(RdTag, {IRB.getInt32(0), + ::llvm::ConstantPointerNull::get(IRB.getPtrTy())}); + Base->setName("basetag"); + return Base; +} + +bool WebAssemblyStackTagging::runOnFunction(Function &Fn) { + if (!Fn.hasFnAttribute(Attribute::SanitizeMemTag)) + return false; + + Triple triplet(Fn.getParent()->getTargetTriple()); + bool iswasm32 = triplet.getArch() == ::llvm::Triple::wasm32; + + F = &Fn; + DL = &Fn.getParent()->getDataLayout(); + + OptimizationRemarkEmitter &ORE = + getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE(); + + SSI = &getAnalysis<StackSafetyGlobalInfoWrapperPass>().getResult(); + memtag::StackInfoBuilder SIB(SSI, "webassembly-stack-tagging"); + for (Instruction &I : instructions(F)) + SIB.visit(ORE, I); + memtag::StackInfo &SInfo = SIB.get(); + + std::unique_ptr<DominatorTree> DeleteDT; + DominatorTree *DT = nullptr; + if (auto *P = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) + DT = &P->getDomTree(); + + if (DT == nullptr) { + DeleteDT = std::make_unique<DominatorTree>(*F); + DT = DeleteDT.get(); + } + + std::unique_ptr<PostDominatorTree> DeletePDT; + PostDominatorTree *PDT = nullptr; + if (auto *P = getAnalysisIfAvailable<PostDominatorTreeWrapperPass>()) + PDT = &P->getPostDomTree(); + + if (PDT == nullptr) { + DeletePDT = std::make_unique<PostDominatorTree>(*F); + PDT = DeletePDT.get(); + } + + std::unique_ptr<LoopInfo> DeleteLI; + LoopInfo *LI = nullptr; + if (auto *LIWP = getAnalysisIfAvailable<LoopInfoWrapperPass>()) { + LI = &LIWP->getLoopInfo(); + } else { + DeleteLI = std::make_unique<LoopInfo>(*DT); + LI = DeleteLI.get(); + } + auto &AllocasToInstrument = SInfo.AllocasToInstrument; + if (AllocasToInstrument.empty()) { + return true; + } + Instruction *Base = nullptr; + bool usehint = false; + if (1 < AllocasToInstrument.size()) { + Base = insertBaseTaggedPointer(AllocasToInstrument, DT); + usehint = true; + } + uint64_t NextTag = 0; + LLVMContext &Ctx = Fn.getContext(); + Type *Int32Type = llvm::Type::getInt32Ty(Ctx); + Type *Int64Type = llvm::Type::getInt64Ty(Ctx); + Type *IntPtrType = iswasm32 ? Int32Type : Int64Type; + + Function *UntagStoreDecl = Intrinsic::getOrInsertDeclaration( + F->getParent(), Intrinsic::wasm_memtag_untagstore, {IntPtrType}); + + for (auto &I : AllocasToInstrument) { + memtag::AllocaInfo &Info = I.second; + memtag::alignAndPadAlloca(Info, kTagGranuleSize); + uint64_t Tag = NextTag; + if (iswasm32) { + Tag = static_cast<uint32_t>(Tag); + } + ++NextTag; + AllocaInst *AI = Info.AI; + IRBuilder<> IRB(Info.AI->getNextNode()); + + // Calls to functions that may return twice (e.g. setjmp) confuse the + // postdominator analysis, and will leave us to keep memory tagged after + // function return. Work around this by always untagging at every return + // statement if return_twice functions are called. + bool SupportedLifetime = + memtag::isSupportedLifetime(Info, DT, LI) && !SInfo.CallsReturnTwice; + if (SupportedLifetime) { + bool combineStore{canCombineStore(Info, AI, DT)}; + Function *StoreTagDecl = nullptr; + Intrinsic::ID SelectedIntrinsicID; + + if (combineStore) { + SelectedIntrinsicID = usehint ? Intrinsic::wasm_memtag_hintstore + : Intrinsic::wasm_memtag_randomstore; + } else { + SelectedIntrinsicID = usehint ? Intrinsic::wasm_memtag_hint + : Intrinsic::wasm_memtag_random; + StoreTagDecl = Intrinsic::getOrInsertDeclaration( + F->getParent(), Intrinsic::wasm_memtag_store, {IntPtrType}); + } + + SmallVector<Type *, 2> SelectedStoreSignatureTypes; + if (combineStore) { + SelectedStoreSignatureTypes.push_back(IntPtrType); + } + if (usehint) { + SelectedStoreSignatureTypes.push_back(IntPtrType); + } + uint64_t Size = *Info.AI->getAllocationSize(*DL); + Size = alignTo(Size, kTagGranuleSize); + + auto *RandomOrHintMayStoreTagDecl = Intrinsic::getOrInsertDeclaration( + F->getParent(), SelectedIntrinsicID, SelectedStoreSignatureTypes); + + SmallVector<Value *, 5> TagCallArguments{ConstantInt::get(Int32Type, 0), + Info.AI}; + if (combineStore) { + TagCallArguments.push_back(ConstantInt::get(IntPtrType, Size)); + } + if (usehint) { + TagCallArguments.push_back(Base); + TagCallArguments.push_back(ConstantInt::get(IntPtrType, Tag)); + } + if (combineStore) { + IntrinsicInst *Start = Info.LifetimeStart.front(); + IRBuilder<> IRBStart(Start->getNextNode()); + CallInst *TagPCall = + IRBStart.CreateCall(RandomOrHintMayStoreTagDecl, TagCallArguments); + if (Info.AI->hasName()) + TagPCall->setName(Info.AI->getName() + ".tag"); + + Info.AI->replaceUsesWithIf(TagPCall, [&](const Use &U) { + return U.getUser() != TagPCall && + !isa<LifetimeIntrinsic>(U.getUser()); + }); + TagPCall->setOperand(1, Info.AI); + IntrinsicInst *End = Info.LifetimeEnd.front(); + IRBuilder<> IRBEnd(End); + IRBEnd.CreateCall(UntagStoreDecl, + {ConstantInt::get(Int32Type, 0), Info.AI, + ConstantInt::get(IntPtrType, Size)}); + Start->eraseFromParent(); + End->eraseFromParent(); + } else { + auto *TagPCall = + IRB.CreateCall(RandomOrHintMayStoreTagDecl, TagCallArguments); + + if (Info.AI->hasName()) + TagPCall->setName(Info.AI->getName() + ".tag"); + + Info.AI->replaceUsesWithIf(TagPCall, [&](const Use &U) { + return !isa<LifetimeIntrinsic>(U.getUser()); + }); + + TagPCall->setOperand(1, Info.AI); + + for (IntrinsicInst *Start : Info.LifetimeStart) { + IRBuilder<> IRB2(Start->getNextNode()); + IRB2.CreateCall(StoreTagDecl, + {ConstantInt::get(Int32Type, 0), TagPCall, + ConstantInt::get(IntPtrType, Size)}); + } + auto TagEnd = [&](Instruction *Node) { + untagAlloca(AI, Node, Size, UntagStoreDecl, IntPtrType); + }; + memtag::forAllReachableExits(*DT, *PDT, *LI, Info, SInfo.RetVec, + TagEnd); + } + } else { + uint64_t Size = *Info.AI->getAllocationSize(*DL); + Intrinsic::ID SelectedStoreIntrinsicID = + usehint ? Intrinsic::wasm_memtag_hintstore + : Intrinsic::wasm_memtag_randomstore; + SmallVector<Type *, 2> SelectedStoreSignatureTypes{IntPtrType}; + if (usehint) { + SelectedStoreSignatureTypes.push_back(IntPtrType); + } + auto *RandomOrHintStoreTagDecl = Intrinsic::getOrInsertDeclaration( + F->getParent(), SelectedStoreIntrinsicID, + SelectedStoreSignatureTypes); + + SmallVector<Value *, 5> StoreTagCallArguments{ + ConstantInt::get(Int32Type, 0), Info.AI, + ConstantInt::get(IntPtrType, Size)}; + if (usehint) { + StoreTagCallArguments.push_back(Base); + StoreTagCallArguments.push_back(ConstantInt::get(IntPtrType, Tag)); + } + + auto *TagPCall = + IRB.CreateCall(RandomOrHintStoreTagDecl, StoreTagCallArguments); + if (Info.AI->hasName()) + TagPCall->setName(Info.AI->getName() + ".tag"); + Info.AI->replaceAllUsesWith(TagPCall); + TagPCall->setOperand(1, Info.AI); + for (auto *RI : SInfo.RetVec) { + untagAlloca(AI, RI, Size, UntagStoreDecl, IntPtrType); + } + // We may have inserted tag/untag outside of any lifetime interval. + // Remove all lifetime intrinsics for this alloca. + for (auto *II : Info.LifetimeStart) + II->eraseFromParent(); + for (auto *II : Info.LifetimeEnd) + II->eraseFromParent(); + } + + memtag::annotateDebugRecords(Info, static_cast<unsigned long>(Tag)); + } + + return true; +} + +char WebAssemblyStackTagging::ID = 0; +INITIALIZE_PASS_BEGIN(WebAssemblyStackTagging, DEBUG_TYPE, + "WebAssembly Stack Tagging", false, false) +#if 0 +INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) +#endif +INITIALIZE_PASS_DEPENDENCY(StackSafetyGlobalInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) +INITIALIZE_PASS_END(WebAssemblyStackTagging, DEBUG_TYPE, + "WebAssembly Stack Tagging", false, false) + +FunctionPass *llvm::createWebAssemblyStackTaggingPass() { + return new WebAssemblyStackTagging(); +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h index 149c49dd34473..8e5db9522e3f1 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -55,6 +55,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool HasMutableGlobals = false; bool HasNontrappingFPToInt = false; bool HasReferenceTypes = false; + bool HasMemtag = false; bool HasRelaxedAtomics = false; bool HasSignExt = false; bool HasTailCall = false; @@ -123,6 +124,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool hasMutableGlobals() const { return HasMutableGlobals; } bool hasNontrappingFPToInt() const { return HasNontrappingFPToInt; } bool hasReferenceTypes() const { return HasReferenceTypes; } + bool hasMemtag() const { return HasMemtag; } bool hasRelaxedAtomics() const { return HasRelaxedAtomics; } bool hasRelaxedSIMD() const { return SIMDLevel >= RelaxedSIMD; } bool hasSignExt() const { return HasSignExt; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 066e8329e7f39..ce7b06b7e71ca 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -115,6 +115,8 @@ LLVMInitializeWebAssemblyTarget() { initializeWebAssemblyMCLowerPreLegacyPass(PR); initializeWebAssemblyFixBrTableDefaultsLegacyPass(PR); initializeWebAssemblyDAGToDAGISelLegacyPass(PR); + initializeWebAssemblyStackTaggingPass(PR); + initializeWebAssemblyGlobalsTaggingPass(PR); } //===----------------------------------------------------------------------===// @@ -319,6 +321,9 @@ void WebAssemblyPassConfig::addIRPasses() { if (getOptLevel() != CodeGenOptLevel::None) addPass(createWebAssemblyOptimizeReturnedLegacyPass()); + addPass(createWebAssemblyGlobalsTaggingPass()); + addPass(createWebAssemblyStackTaggingPass()); + // If exception handling is not enabled and setjmp/longjmp handling is // enabled, we lower invokes into calls and delete unreachable landingpad // blocks. Lowering invokes when there is no EH support is done in diff --git a/llvm/test/CodeGen/WebAssembly/memtag-addr32.ll b/llvm/test/CodeGen/WebAssembly/memtag-addr32.ll new file mode 100644 index 0000000000000..222e110f41f60 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/memtag-addr32.ll @@ -0,0 +1,282 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +; --- 0xfc20: memtag.status --- +; CHECK-LABEL: test_status: +; CHECK: memtag.status 0 +define i32 @test_status() { + %1 = call i32 @llvm.wasm.memtag.status.i32(i32 0) + ret i32 %1 +} + +; --- 0xfc21: memtag.extract --- +; CHECK-LABEL: test_extract: +; CHECK: local.get 0 +; CHECK: memtag.extract 0 +define i32 @test_extract(ptr %p) { + %1 = call i32 @llvm.wasm.memtag.extract.i32(i32 0, ptr %p) + ret i32 %1 +} + +; --- 0xfc22: memtag.insert --- +; CHECK-LABEL: test_insert: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.insert 0 +define ptr @test_insert(ptr %p, i32 %v) { + %1 = call ptr @llvm.wasm.memtag.insert.i32(i32 0, ptr %p, i32 %v) + ret ptr %1 +} + +; --- 0xfc23: memtag.tagbits --- +; CHECK-LABEL: test_tagbits: +; CHECK: memtag.tagbits 0 +define i32 @test_tagbits() { + %1 = call i32 @llvm.wasm.memtag.tagbits.i32(i32 0) + ret i32 %1 +} + +; --- 0xfc24: memtag.startbit --- +; CHECK-LABEL: test_startbit: +; CHECK: memtag.startbit 0 +define i32 @test_startbit() { + %1 = call i32 @llvm.wasm.memtag.startbit.i32(i32 0) + ret i32 %1 +} + +; --- 0xfc25: memtag.copy --- +; CHECK-LABEL: test_copy: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.copy 0 +define ptr @test_copy(ptr %d, ptr %s) { + %1 = call ptr @llvm.wasm.memtag.copy(i32 0, ptr %d, ptr %s) + ret ptr %1 +} + +; --- 0xfc26: memtag.sub --- +; CHECK-LABEL: test_sub: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.sub 0 +define i32 @test_sub(ptr %a, ptr %b) { + %1 = call i32 @llvm.wasm.memtag.sub.i32(i32 0, ptr %a, ptr %b) + ret i32 %1 +} + +; --- 0xfc27: memtag.load --- +; CHECK-LABEL: test_load: +; CHECK: local.get 0 +; CHECK: memtag.load 0 +define ptr @test_load(ptr %p) { + %1 = call ptr @llvm.wasm.memtag.load(i32 0, ptr %p) + ret ptr %1 +} + +; --- 0xfc28: memtag.untag --- +; CHECK-LABEL: test_untag: +; CHECK: local.get 0 +; CHECK: memtag.untag 0 +define ptr @test_untag(ptr %p) { + %1 = call ptr @llvm.wasm.memtag.untag(i32 0, ptr %p) + ret ptr %1 +} + +; --- 0xfc29: memtag.untagstore --- +; CHECK-LABEL: test_untagstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.untagstore 0 +define ptr @test_untagstore(ptr %p, i32 %v) { + %1 = call ptr @llvm.wasm.memtag.untagstore.i32(i32 0, ptr %p, i32 %v) + ret ptr %1 +} + +; --- 0xfc2a: memtag.untagstorez --- +; CHECK-LABEL: test_untagstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.untagstorez 0 +define ptr @test_untagstorez(ptr %p, i32 %v) { + %1 = call ptr @llvm.wasm.memtag.untagstorez.i32(i32 0, ptr %p, i32 %v) + ret ptr %1 +} + +; --- 0xfc2b: memtag.store --- +; CHECK-LABEL: test_store: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.store 0 +define void @test_store(ptr %p, i32 %v) { + call void @llvm.wasm.memtag.store.i32(i32 0, ptr %p, i32 %v) + ret void +} + +; --- 0xfc2c: memtag.storez --- +; CHECK-LABEL: test_storez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.storez 0 +define void @test_storez(ptr %p, i32 %v) { + call void @llvm.wasm.memtag.storez.i32(i32 0, ptr %p, i32 %v) + ret void +} + +; --- 0xfc2d: memtag.random --- +; CHECK-LABEL: test_random: +; CHECK: local.get 0 +; CHECK: memtag.random 0 +define ptr @test_random(ptr %p) { + %1 = call ptr @llvm.wasm.memtag.random(i32 0, ptr %p) + ret ptr %1 +} + +; --- 0xfc2e: memtag.randomstore --- +; CHECK-LABEL: test_randomstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.randomstore 0 +define ptr @test_randomstore(ptr %p, i32 %v) { + %1 = call ptr @llvm.wasm.memtag.randomstore.i32(i32 0, ptr %p, i32 %v) + ret ptr %1 +} + +; --- 0xfc2f: memtag.randomstorez --- +; CHECK-LABEL: test_randomstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.randomstorez 0 +define ptr @test_randomstorez(ptr %p, i32 %v) { + %1 = call ptr @llvm.wasm.memtag.randomstorez.i32(i32 0, ptr %p, i32 %v) + ret ptr %1 +} + +; --- 0xfc30: memtag.randommask --- +; CHECK-LABEL: test_randommask: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.randommask 0 +define ptr @test_randommask(ptr %p, i32 %m) { + %1 = call ptr @llvm.wasm.memtag.randommask.i32(i32 0, ptr %p, i32 %m) + ret ptr %1 +} + +; --- 0xfc31: memtag.randommaskstore --- +; CHECK-LABEL: test_randommaskstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.randommaskstore 0 +define ptr @test_randommaskstore(ptr %p, i32 %v, i32 %m) { + %1 = call ptr @llvm.wasm.memtag.randommaskstore.i32(i32 0, ptr %p, i32 %v, i32 %m) + ret ptr %1 +} + +; --- 0xfc32: memtag.randommaskstorez --- +; CHECK-LABEL: test_randommaskstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.randommaskstorez 0 +define ptr @test_randommaskstorez(ptr %p, i32 %v, i32 %m) { + %1 = call ptr @llvm.wasm.memtag.randommaskstorez.i32(i32 0, ptr %p, i32 %v, i32 %m) + ret ptr %1 +} + +; --- 0xfc33: memtag.add --- +; CHECK-LABEL: test_add: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.add 0 +define ptr @test_add(ptr %p, i32 %o, i32 %t) { + %1 = call ptr @llvm.wasm.memtag.add.i32(i32 0, ptr %p, i32 %o, i32 %t) + ret ptr %1 +} + +; --- 0xfc34: memtag.addstore --- +; CHECK-LABEL: test_addstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.addstore 0 +define ptr @test_addstore(ptr %p, i32 %v, i32 %o, i32 %t) { + %1 = call ptr @llvm.wasm.memtag.addstore.i32(i32 0, ptr %p, i32 %v, i32 %o, i32 %t) + ret ptr %1 +} + +; --- 0xfc35: memtag.addstorez --- +; CHECK-LABEL: test_addstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.addstorez 0 +define ptr @test_addstorez(ptr %p, i32 %v, i32 %o, i32 %t) { + %1 = call ptr @llvm.wasm.memtag.addstorez.i32(i32 0, ptr %p, i32 %v, i32 %o, i32 %t) + ret ptr %1 +} + +; --- 0xfc36: memtag.hint --- +; CHECK-LABEL: test_hint: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.hint 0 +define ptr @test_hint(ptr %p, ptr %h, i32 %i) { + %1 = call ptr @llvm.wasm.memtag.hint.i32(i32 0, ptr %p, ptr %h, i32 %i) + ret ptr %1 +} + +; --- 0xfc37: memtag.hintstore --- +; CHECK-LABEL: test_hintstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.hintstore 0 +define ptr @test_hintstore(ptr %p, i32 %v, ptr %h, i32 %i) { + %1 = call ptr @llvm.wasm.memtag.hintstore.i32(i32 0, ptr %p, i32 %v, ptr %h, i32 %i) + ret ptr %1 +} + +; --- 0xfc38: memtag.hintstorez --- +; CHECK-LABEL: test_hintstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.hintstorez 0 +define ptr @test_hintstorez(ptr %p, i32 %v, ptr %h, i32 %i) { + %1 = call ptr @llvm.wasm.memtag.hintstorez.i32(i32 0, ptr %p, i32 %v, ptr %h, i32 %i) + ret ptr %1 +} + +; --- Intrinsic Declarations --- +declare i32 @llvm.wasm.memtag.status.i32(i32) +declare i32 @llvm.wasm.memtag.extract.i32(i32, ptr) +declare ptr @llvm.wasm.memtag.insert.i32(i32, ptr, i32) +declare i32 @llvm.wasm.memtag.tagbits.i32(i32) +declare i32 @llvm.wasm.memtag.startbit.i32(i32) +declare ptr @llvm.wasm.memtag.copy(i32, ptr, ptr) +declare i32 @llvm.wasm.memtag.sub.i32(i32, ptr, ptr) +declare ptr @llvm.wasm.memtag.load(i32, ptr) +declare ptr @llvm.wasm.memtag.untag(i32, ptr) +declare ptr @llvm.wasm.memtag.untagstore.i32(i32, ptr, i32) +declare ptr @llvm.wasm.memtag.untagstorez.i32(i32, ptr, i32) +declare void @llvm.wasm.memtag.store.i32(i32, ptr, i32) +declare void @llvm.wasm.memtag.storez.i32(i32, ptr, i32) +declare ptr @llvm.wasm.memtag.random(i32, ptr) +declare ptr @llvm.wasm.memtag.randomstore.i32(i32, ptr, i32) +declare ptr @llvm.wasm.memtag.randomstorez.i32(i32, ptr, i32) +declare ptr @llvm.wasm.memtag.randommask.i32(i32, ptr, i32) +declare ptr @llvm.wasm.memtag.randommaskstore.i32(i32, ptr, i32, i32) +declare ptr @llvm.wasm.memtag.randommaskstorez.i32(i32, ptr, i32, i32) +declare ptr @llvm.wasm.memtag.add.i32(i32, ptr, i32, i32) +declare ptr @llvm.wasm.memtag.addstore.i32(i32, ptr, i32, i32, i32) +declare ptr @llvm.wasm.memtag.addstorez.i32(i32, ptr, i32, i32, i32) +declare ptr @llvm.wasm.memtag.hint.i32(i32, ptr, ptr, i32) +declare ptr @llvm.wasm.memtag.hintstore.i32(i32, ptr, i32, ptr, i32) +declare ptr @llvm.wasm.memtag.hintstorez.i32(i32, ptr, i32, ptr, i32) diff --git a/llvm/test/CodeGen/WebAssembly/memtag-addr64.ll b/llvm/test/CodeGen/WebAssembly/memtag-addr64.ll new file mode 100644 index 0000000000000..b23100bf0416b --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/memtag-addr64.ll @@ -0,0 +1,282 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +target triple = "wasm64-unknown-unknown" + +; --- 0xfc20: memtag.status --- +; CHECK-LABEL: test_status: +; CHECK: memtag.status 0 +define i64 @test_status() { + %1 = call i64 @llvm.wasm.memtag.status.i64(i32 0) + ret i64 %1 +} + +; --- 0xfc21: memtag.extract --- +; CHECK-LABEL: test_extract: +; CHECK: local.get 0 +; CHECK: memtag.extract 0 +define i64 @test_extract(ptr %p) { + %1 = call i64 @llvm.wasm.memtag.extract.i64(i32 0, ptr %p) + ret i64 %1 +} + +; --- 0xfc22: memtag.insert --- +; CHECK-LABEL: test_insert: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.insert 0 +define ptr @test_insert(ptr %p, i64 %v) { + %1 = call ptr @llvm.wasm.memtag.insert.i64(i32 0, ptr %p, i64 %v) + ret ptr %1 +} + +; --- 0xfc23: memtag.tagbits --- +; CHECK-LABEL: test_tagbits: +; CHECK: memtag.tagbits 0 +define i64 @test_tagbits() { + %1 = call i64 @llvm.wasm.memtag.tagbits.i64(i32 0) + ret i64 %1 +} + +; --- 0xfc24: memtag.startbit --- +; CHECK-LABEL: test_startbit: +; CHECK: memtag.startbit 0 +define i64 @test_startbit() { + %1 = call i64 @llvm.wasm.memtag.startbit.i64(i32 0) + ret i64 %1 +} + +; --- 0xfc25: memtag.copy --- +; CHECK-LABEL: test_copy: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.copy 0 +define ptr @test_copy(ptr %d, ptr %s) { + %1 = call ptr @llvm.wasm.memtag.copy(i32 0, ptr %d, ptr %s) + ret ptr %1 +} + +; --- 0xfc26: memtag.sub --- +; CHECK-LABEL: test_sub: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.sub 0 +define i64 @test_sub(ptr %a, ptr %b) { + %1 = call i64 @llvm.wasm.memtag.sub.i64(i32 0, ptr %a, ptr %b) + ret i64 %1 +} + +; --- 0xfc27: memtag.load --- +; CHECK-LABEL: test_load: +; CHECK: local.get 0 +; CHECK: memtag.load 0 +define ptr @test_load(ptr %p) { + %1 = call ptr @llvm.wasm.memtag.load(i32 0, ptr %p) + ret ptr %1 +} + +; --- 0xfc28: memtag.untag --- +; CHECK-LABEL: test_untag: +; CHECK: local.get 0 +; CHECK: memtag.untag 0 +define ptr @test_untag(ptr %p) { + %1 = call ptr @llvm.wasm.memtag.untag(i32 0, ptr %p) + ret ptr %1 +} + +; --- 0xfc29: memtag.untagstore --- +; CHECK-LABEL: test_untagstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.untagstore 0 +define ptr @test_untagstore(ptr %p, i64 %v) { + %1 = call ptr @llvm.wasm.memtag.untagstore.i64(i32 0, ptr %p, i64 %v) + ret ptr %1 +} + +; --- 0xfc2a: memtag.untagstorez --- +; CHECK-LABEL: test_untagstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.untagstorez 0 +define ptr @test_untagstorez(ptr %p, i64 %v) { + %1 = call ptr @llvm.wasm.memtag.untagstorez.i64(i32 0, ptr %p, i64 %v) + ret ptr %1 +} + +; --- 0xfc2b: memtag.store --- +; CHECK-LABEL: test_store: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.store 0 +define void @test_store(ptr %p, i64 %v) { + call void @llvm.wasm.memtag.store.i64(i32 0, ptr %p, i64 %v) + ret void +} + +; --- 0xfc2c: memtag.storez --- +; CHECK-LABEL: test_storez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.storez 0 +define void @test_storez(ptr %p, i64 %v) { + call void @llvm.wasm.memtag.storez.i64(i32 0, ptr %p, i64 %v) + ret void +} + +; --- 0xfc2d: memtag.random --- +; CHECK-LABEL: test_random: +; CHECK: local.get 0 +; CHECK: memtag.random 0 +define ptr @test_random(ptr %p) { + %1 = call ptr @llvm.wasm.memtag.random(i32 0, ptr %p) + ret ptr %1 +} + +; --- 0xfc2e: memtag.randomstore --- +; CHECK-LABEL: test_randomstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.randomstore 0 +define ptr @test_randomstore(ptr %p, i64 %v) { + %1 = call ptr @llvm.wasm.memtag.randomstore.i64(i32 0, ptr %p, i64 %v) + ret ptr %1 +} + +; --- 0xfc2f: memtag.randomstorez --- +; CHECK-LABEL: test_randomstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.randomstorez 0 +define ptr @test_randomstorez(ptr %p, i64 %v) { + %1 = call ptr @llvm.wasm.memtag.randomstorez.i64(i32 0, ptr %p, i64 %v) + ret ptr %1 +} + +; --- 0xfc30: memtag.randommask --- +; CHECK-LABEL: test_randommask: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: memtag.randommask 0 +define ptr @test_randommask(ptr %p, i64 %m) { + %1 = call ptr @llvm.wasm.memtag.randommask.i64(i32 0, ptr %p, i64 %m) + ret ptr %1 +} + +; --- 0xfc31: memtag.randommaskstore --- +; CHECK-LABEL: test_randommaskstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.randommaskstore 0 +define ptr @test_randommaskstore(ptr %p, i64 %v, i64 %m) { + %1 = call ptr @llvm.wasm.memtag.randommaskstore.i64(i32 0, ptr %p, i64 %v, i64 %m) + ret ptr %1 +} + +; --- 0xfc32: memtag.randommaskstorez --- +; CHECK-LABEL: test_randommaskstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.randommaskstorez 0 +define ptr @test_randommaskstorez(ptr %p, i64 %v, i64 %m) { + %1 = call ptr @llvm.wasm.memtag.randommaskstorez.i64(i32 0, ptr %p, i64 %v, i64 %m) + ret ptr %1 +} + +; --- 0xfc33: memtag.add --- +; CHECK-LABEL: test_add: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.add 0 +define ptr @test_add(ptr %p, i64 %o, i64 %t) { + %1 = call ptr @llvm.wasm.memtag.add.i64(i32 0, ptr %p, i64 %o, i64 %t) + ret ptr %1 +} + +; --- 0xfc34: memtag.addstore --- +; CHECK-LABEL: test_addstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.addstore 0 +define ptr @test_addstore(ptr %p, i64 %v, i64 %o, i64 %t) { + %1 = call ptr @llvm.wasm.memtag.addstore.i64(i32 0, ptr %p, i64 %v, i64 %o, i64 %t) + ret ptr %1 +} + +; --- 0xfc35: memtag.addstorez --- +; CHECK-LABEL: test_addstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.addstorez 0 +define ptr @test_addstorez(ptr %p, i64 %v, i64 %o, i64 %t) { + %1 = call ptr @llvm.wasm.memtag.addstorez.i64(i32 0, ptr %p, i64 %v, i64 %o, i64 %t) + ret ptr %1 +} + +; --- 0xfc36: memtag.hint --- +; CHECK-LABEL: test_hint: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: memtag.hint 0 +define ptr @test_hint(ptr %p, ptr %h, i64 %i) { + %1 = call ptr @llvm.wasm.memtag.hint.i64(i32 0, ptr %p, ptr %h, i64 %i) + ret ptr %1 +} + +; --- 0xfc37: memtag.hintstore --- +; CHECK-LABEL: test_hintstore: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.hintstore 0 +define ptr @test_hintstore(ptr %p, i64 %v, ptr %h, i64 %i) { + %1 = call ptr @llvm.wasm.memtag.hintstore.i64(i32 0, ptr %p, i64 %v, ptr %h, i64 %i) + ret ptr %1 +} + +; --- 0xfc38: memtag.hintstorez --- +; CHECK-LABEL: test_hintstorez: +; CHECK: local.get 0 +; CHECK: local.get 1 +; CHECK: local.get 2 +; CHECK: local.get 3 +; CHECK: memtag.hintstorez 0 +define ptr @test_hintstorez(ptr %p, i64 %v, ptr %h, i64 %i) { + %1 = call ptr @llvm.wasm.memtag.hintstorez.i64(i32 0, ptr %p, i64 %v, ptr %h, i64 %i) + ret ptr %1 +} + +; --- Intrinsic Declarations --- +declare i64 @llvm.wasm.memtag.status.i64(i32) +declare i64 @llvm.wasm.memtag.extract.i64(i32, ptr) +declare ptr @llvm.wasm.memtag.insert.i64(i32, ptr, i64) +declare i64 @llvm.wasm.memtag.tagbits.i64(i32) +declare i64 @llvm.wasm.memtag.startbit.i64(i32) +declare ptr @llvm.wasm.memtag.copy(i32, ptr, ptr) +declare i64 @llvm.wasm.memtag.sub.i64(i32, ptr, ptr) +declare ptr @llvm.wasm.memtag.load(i32, ptr) +declare ptr @llvm.wasm.memtag.untag(i32, ptr) +declare ptr @llvm.wasm.memtag.untagstore.i64(i32, ptr, i64) +declare ptr @llvm.wasm.memtag.untagstorez.i64(i32, ptr, i64) +declare void @llvm.wasm.memtag.store.i64(i32, ptr, i64) +declare void @llvm.wasm.memtag.storez.i64(i32, ptr, i64) +declare ptr @llvm.wasm.memtag.random(i32, ptr) +declare ptr @llvm.wasm.memtag.randomstore.i64(i32, ptr, i64) +declare ptr @llvm.wasm.memtag.randomstorez.i64(i32, ptr, i64) +declare ptr @llvm.wasm.memtag.randommask.i64(i32, ptr, i64) +declare ptr @llvm.wasm.memtag.randommaskstore.i64(i32, ptr, i64, i64) +declare ptr @llvm.wasm.memtag.randommaskstorez.i64(i32, ptr, i64, i64) +declare ptr @llvm.wasm.memtag.add.i64(i32, ptr, i64, i64) +declare ptr @llvm.wasm.memtag.addstore.i64(i32, ptr, i64, i64, i64) +declare ptr @llvm.wasm.memtag.addstorez.i64(i32, ptr, i64, i64, i64) +declare ptr @llvm.wasm.memtag.hint.i64(i32, ptr, ptr, i64) +declare ptr @llvm.wasm.memtag.hintstore.i64(i32, ptr, i64, ptr, i64) +declare ptr @llvm.wasm.memtag.hintstorez.i64(i32, ptr, i64, ptr, i64) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
