[llvm] 0eb694b - [RISC-V][HWASAN] Add support for HWASAN code instrumentation for RISC-V

Alexey Baturo via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 13 07:01:23 PST 2022


Author: Alexey Baturo
Date: 2022-12-13T18:00:54+03:00
New Revision: 0eb694bec09df488bb6ab33d0207b6b061718d98

URL: https://github.com/llvm/llvm-project/commit/0eb694bec09df488bb6ab33d0207b6b061718d98
DIFF: https://github.com/llvm/llvm-project/commit/0eb694bec09df488bb6ab33d0207b6b061718d98.diff

LOG: [RISC-V][HWASAN] Add support for HWASAN code instrumentation for RISC-V

Reviewed by: vitalybuka

Differential Revision: https://reviews.llvm.org/D131575

Added: 
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca-with-calls.ll
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca.ll
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/atomic.ll
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/basic.ll
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/exception-lifetime.ll
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/stack-safety-analysis.ll
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/use-after-scope-setjmp.ll
    llvm/test/Instrumentation/HWAddressSanitizer/RISCV/with-calls.ll

Modified: 
    llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index 066eca3bbfece..cebe06b5a3195 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -43,6 +43,7 @@
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/Module.h"
+#include "llvm/IR/NoFolder.h"
 #include "llvm/IR/Type.h"
 #include "llvm/IR/Value.h"
 #include "llvm/Support/Casting.h"
@@ -582,7 +583,8 @@ void HWAddressSanitizer::initializeModule() {
   UseShortGranules =
       ClUseShortGranules.getNumOccurrences() ? ClUseShortGranules : NewRuntime;
   OutlinedChecks =
-      TargetTriple.isAArch64() && TargetTriple.isOSBinFormatELF() &&
+      (TargetTriple.isAArch64() || TargetTriple.isRISCV64()) &&
+      TargetTriple.isOSBinFormatELF() &&
       (ClInlineAllChecks.getNumOccurrences() ? !ClInlineAllChecks : !Recover);
 
   if (ClMatchAllTag.getNumOccurrences()) {
@@ -795,7 +797,8 @@ static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
 }
 
 void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) {
-  if (TargetTriple.isAArch64() || TargetTriple.getArch() == Triple::x86_64)
+  if (TargetTriple.isAArch64() || TargetTriple.getArch() == Triple::x86_64 ||
+      TargetTriple.isRISCV64())
     return;
 
   IRBuilder<> IRB(I);
@@ -913,6 +916,13 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite,
         "{x0}",
         /*hasSideEffects=*/true);
     break;
+  case Triple::riscv64:
+    // The signal handler will find the data address in x10.
+    Asm = InlineAsm::get(
+        FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false),
+        "ebreak\naddiw x0, x0, " + itostr(0x40 + AccessInfo), "{x10}", "{x11}",
+        /*hasSideEffects=*/true);
+    break;
   default:
     report_fatal_error("unsupported architecture");
   }

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca-with-calls.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca-with-calls.ll
new file mode 100644
index 0000000000000..06cd112bd6faa
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca-with-calls.ll
@@ -0,0 +1,23 @@
+; Test alloca instrumentation when tags are generated by HWASan function.
+;
+; RUN: opt < %s -passes=hwasan -hwasan-generate-tags-with-calls -S | FileCheck %s
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+declare void @use32(i32*)
+
+define void @test_alloca() sanitize_hwaddress {
+; CHECK-LABEL: @test_alloca(
+; CHECK: %[[BC:[^ ]*]] = bitcast { i32, [12 x i8] }* %x to i32*
+; CHECK: %[[T1:[^ ]*]] = call i8 @__hwasan_generate_tag()
+; CHECK: %[[A:[^ ]*]] = zext i8 %[[T1]] to i64
+; CHECK: %[[B:[^ ]*]] = ptrtoint i32* %[[BC]] to i64
+; CHECK: %[[C:[^ ]*]] = shl i64 %[[A]], 56
+; CHECK: or i64 %[[B]], %[[C]]
+
+entry:
+  %x = alloca i32, align 4
+  call void @use32(i32* nonnull %x)
+  ret void
+}

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca.ll
new file mode 100644
index 0000000000000..128bd82d16e33
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca.ll
@@ -0,0 +1,80 @@
+; Test alloca instrumentation.
+;
+; RUN: opt < %s -passes=hwasan -hwasan-with-ifunc=1 -S | FileCheck %s --check-prefixes=CHECK,DYNAMIC-SHADOW,NO-UAR-TAGS
+; RUN: opt < %s -passes=hwasan -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ZERO-BASED-SHADOW,NO-UAR-TAGS
+; RUN: opt < %s -passes=hwasan -hwasan-with-ifunc=1 -hwasan-uar-retag-to-zero=0 -S | FileCheck %s --check-prefixes=CHECK,DYNAMIC-SHADOW,UAR-TAGS
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+declare void @use32(i32*)
+
+define void @test_alloca() sanitize_hwaddress !dbg !15 {
+; CHECK-LABEL: @test_alloca(
+; CHECK: %[[FP:[^ ]*]] = call i8* @llvm.frameaddress.p0i8(i32 0)
+; CHECK: %[[A:[^ ]*]] = ptrtoint i8* %[[FP]] to i64
+; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 20
+; CHECK: %[[BASE_TAG:[^ ]*]] = xor i64 %[[A]], %[[B]]
+
+; CHECK: %[[X:[^ ]*]] = alloca { i32, [12 x i8] }, align 16
+; CHECK: %[[X_BC:[^ ]*]] = bitcast { i32, [12 x i8] }* %[[X]] to i32*
+; CHECK: %[[X_TAG:[^ ]*]] = xor i64 %[[BASE_TAG]], 0
+; CHECK: %[[X1:[^ ]*]] = ptrtoint i32* %[[X_BC]] to i64
+; CHECK: %[[C:[^ ]*]] = shl i64 %[[X_TAG]], 56
+; CHECK: %[[D:[^ ]*]] = or i64 %[[X1]], %[[C]]
+; CHECK: %[[X_HWASAN:[^ ]*]] = inttoptr i64 %[[D]] to i32*
+
+; CHECK: %[[X_TAG2:[^ ]*]] = trunc i64 %[[X_TAG]] to i8
+; CHECK: %[[E:[^ ]*]] = ptrtoint i32* %[[X_BC]] to i64
+; CHECK: %[[F:[^ ]*]] = lshr i64 %[[E]], 4
+; DYNAMIC-SHADOW: %[[X_SHADOW:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %[[F]]
+; ZERO-BASED-SHADOW: %[[X_SHADOW:[^ ]*]] = inttoptr i64 %[[F]] to i8*
+; CHECK: %[[X_SHADOW_GEP:[^ ]*]] = getelementptr i8, i8* %[[X_SHADOW]], i32 0
+; CHECK: store i8 4, i8* %[[X_SHADOW_GEP]]
+; CHECK: %[[X_I8:[^ ]*]] = bitcast i32* %[[X_BC]] to i8*
+; CHECK: %[[X_I8_GEP:[^ ]*]] = getelementptr i8, i8* %[[X_I8]], i32 15
+; CHECK: store i8 %[[X_TAG2]], i8* %[[X_I8_GEP]]
+; CHECK: call void @llvm.dbg.value(
+; CHECK-SAME: metadata !DIArgList(i32* %[[X_BC]], i32* %[[X_BC]])
+; CHECK-SAME: metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_tag_offset, 0, DW_OP_LLVM_arg, 1, DW_OP_LLVM_tag_offset, 0,
+; CHECK: call void @use32(i32* nonnull %[[X_HWASAN]])
+
+; UAR-TAGS: %[[BASE_TAG_COMPL:[^ ]*]] = xor i64 %[[BASE_TAG]], 255
+; UAR-TAGS: %[[X_TAG_UAR:[^ ]*]] = trunc i64 %[[BASE_TAG_COMPL]] to i8
+; CHECK: %[[E2:[^ ]*]] = ptrtoint i32* %[[X_BC]] to i64
+; CHECK: %[[F2:[^ ]*]] = lshr i64 %[[E2]], 4
+; DYNAMIC-SHADOW: %[[X_SHADOW2:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %[[F2]]
+; ZERO-BASED-SHADOW: %[[X_SHADOW2:[^ ]*]] = inttoptr i64 %[[F2]] to i8*
+; NO-UAR-TAGS: call void @llvm.memset.p0i8.i64(i8* align 1 %[[X_SHADOW2]], i8 0, i64 1, i1 false)
+; UAR-TAGS: call void @llvm.memset.p0i8.i64(i8* align 1 %[[X_SHADOW2]], i8 %[[X_TAG_UAR]], i64 1, i1 false)
+; CHECK: ret void
+
+
+entry:
+  %x = alloca i32, align 4
+  call void @llvm.dbg.value(metadata !DIArgList(i32* %x, i32* %x), metadata !22, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_deref)), !dbg !21
+  call void @use32(i32* nonnull %x), !dbg !23
+  ret void, !dbg !24
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4}
+!llvm.ident = !{!14}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "alloca.cpp", directory: "/")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = !{!"clang version 13.0.0"}
+!15 = distinct !DISubprogram(name: "test_alloca", linkageName: "_Z11test_allocav", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+!16 = !DISubroutineType(types: !17)
+!17 = !{null}
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64)
+!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!21 = !DILocation(line: 0, scope: !15)
+!22 = !DILocalVariable(name: "x", scope: !15, file: !1, line: 5, type: !20)
+!23 = !DILocation(line: 7, column: 5, scope: !15)
+!24 = !DILocation(line: 8, column: 1, scope: !15)

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/atomic.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/atomic.ll
new file mode 100644
index 0000000000000..788a557d9452c
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/atomic.ll
@@ -0,0 +1,30 @@
+; Test basic address sanitizer instrumentation.
+;
+; RUN: opt < %s -passes=hwasan -S | FileCheck %s
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+define void @atomicrmw(i64* %ptr) sanitize_hwaddress {
+; CHECK-LABEL: @atomicrmw(
+; CHECK: [[PTRI8:%[^ ]*]] = bitcast i64* %ptr to i8*
+; CHECK: call void @llvm.hwasan.check.memaccess.shortgranules({{.*}}, i8* [[PTRI8]], i32 19)
+; CHECK: atomicrmw add i64* %ptr, i64 1 seq_cst
+; CHECK: ret void
+
+entry:
+  %0 = atomicrmw add i64* %ptr, i64 1 seq_cst
+  ret void
+}
+
+define void @cmpxchg(i64* %ptr, i64 %compare_to, i64 %new_value) sanitize_hwaddress {
+; CHECK-LABEL: @cmpxchg(
+; CHECK: [[PTRI8:%[^ ]*]] = bitcast i64* %ptr to i8*
+; CHECK: call void @llvm.hwasan.check.memaccess.shortgranules({{.*}}, i8* [[PTRI8]], i32 19)
+; CHECK: cmpxchg i64* %ptr, i64 %compare_to, i64 %new_value seq_cst seq_cst
+; CHECK: ret void
+
+entry:
+  %0 = cmpxchg i64* %ptr, i64 %compare_to, i64 %new_value seq_cst seq_cst
+  ret void
+}

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/basic.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/basic.ll
new file mode 100644
index 0000000000000..f70ec8cd8a926
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/basic.ll
@@ -0,0 +1,409 @@
+; Test basic address sanitizer instrumentation.
+;
+; RUN: opt < %s -passes=hwasan -hwasan-recover=0 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT
+; RUN: opt < %s -passes=hwasan -hwasan-recover=1 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-DYNAMIC-SHADOW
+; RUN: opt < %s -passes=hwasan -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT
+; RUN: opt < %s -passes=hwasan -hwasan-recover=1 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-ZERO-BASED-SHADOW
+
+; CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (void ()* @hwasan.module_ctor to i8*)]
+; CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @hwasan.module_ctor, i8* bitcast (void ()* @hwasan.module_ctor to i8*) }]
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+define i8 @test_load8(i8* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load8(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label %[[MISMATCH:[0-9]*]], label %[[CONT:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[MISMATCH]]:
+; RECOVER: %[[NOTSHORT:[^ ]*]] = icmp ugt i8 %[[MEMTAG]], 15
+; RECOVER: br i1 %[[NOTSHORT]], label %[[FAIL:[0-9]*]], label %[[SHORT:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[FAIL]]:
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 96", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; RECOVER: [[SHORT]]:
+; RECOVER: %[[LOWBITS:[^ ]*]] = and i64 %[[A]], 15
+; RECOVER: %[[LOWBITS_I8:[^ ]*]] = trunc i64 %[[LOWBITS]] to i8
+; RECOVER: %[[LAST:[^ ]*]] = add i8 %[[LOWBITS_I8]], 0
+; RECOVER: %[[OOB:[^ ]*]] = icmp uge i8 %[[LAST]], %[[MEMTAG]]
+; RECOVER: br i1 %[[OOB]], label %[[FAIL]], label %[[INBOUNDS:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[INBOUNDS]]:
+; RECOVER: %[[EOG_ADDR:[^ ]*]] = or i64 %[[C]], 15
+; RECOVER: %[[EOG_PTR:[^ ]*]] = inttoptr i64 %[[EOG_ADDR]] to i8*
+; RECOVER: %[[EOGTAG:[^ ]*]] = load i8, i8* %[[EOG_PTR]]
+; RECOVER: %[[EOG_MISMATCH:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[EOGTAG]]
+; RECOVER: br i1 %[[EOG_MISMATCH]], label %[[FAIL]], label %[[CONT1:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[CONT1]]:
+; RECOVER: br label %[[CONT]]
+
+; RECOVER: [[CONT]]:
+
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %a, i32 0)
+
+; CHECK: %[[G:[^ ]*]] = load i8, i8* %a, align 4
+; CHECK: ret i8 %[[G]]
+
+entry:
+  %b = load i8, i8* %a, align 4
+  ret i8 %b
+}
+
+define i16 @test_load16(i16* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load16(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label %[[MISMATCH:[0-9]*]], label %[[CONT:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[MISMATCH]]:
+; RECOVER: %[[NOTSHORT:[^ ]*]] = icmp ugt i8 %[[MEMTAG]], 15
+; RECOVER: br i1 %[[NOTSHORT]], label %[[FAIL:[0-9]*]], label %[[SHORT:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[FAIL]]:
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 97", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; RECOVER: [[SHORT]]:
+; RECOVER: %[[LOWBITS:[^ ]*]] = and i64 %[[A]], 15
+; RECOVER: %[[LOWBITS_I8:[^ ]*]] = trunc i64 %[[LOWBITS]] to i8
+; RECOVER: %[[LAST:[^ ]*]] = add i8 %[[LOWBITS_I8]], 1
+; RECOVER: %[[OOB:[^ ]*]] = icmp uge i8 %[[LAST]], %[[MEMTAG]]
+; RECOVER: br i1 %[[OOB]], label %[[FAIL]], label %[[INBOUNDS:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[INBOUNDS]]:
+; RECOVER: %[[EOG_ADDR:[^ ]*]] = or i64 %[[C]], 15
+; RECOVER: %[[EOG_PTR:[^ ]*]] = inttoptr i64 %[[EOG_ADDR]] to i8*
+; RECOVER: %[[EOGTAG:[^ ]*]] = load i8, i8* %[[EOG_PTR]]
+; RECOVER: %[[EOG_MISMATCH:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[EOGTAG]]
+; RECOVER: br i1 %[[EOG_MISMATCH]], label %[[FAIL]], label %[[CONT1:[0-9]*]], !prof {{.*}}
+
+; RECOVER: [[CONT1]]:
+; RECOVER: br label %[[CONT]]
+
+; RECOVER: [[CONT]]:
+
+; ABORT: %[[A:[^ ]*]] = bitcast i16* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 1)
+
+; CHECK: %[[G:[^ ]*]] = load i16, i16* %a, align 4
+; CHECK: ret i16 %[[G]]
+
+entry:
+  %b = load i16, i16* %a, align 4
+  ret i16 %b
+}
+
+define i32 @test_load32(i32* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load32(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 98", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: %[[A:[^ ]*]] = bitcast i32* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 2)
+
+; CHECK: %[[G:[^ ]*]] = load i32, i32* %a, align 4
+; CHECK: ret i32 %[[G]]
+
+entry:
+  %b = load i32, i32* %a, align 4
+  ret i32 %b
+}
+
+define i64 @test_load64(i64* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load64(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 99", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: %[[A:[^ ]*]] = bitcast i64* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 3)
+
+; CHECK: %[[G:[^ ]*]] = load i64, i64* %a, align 8
+; CHECK: ret i64 %[[G]]
+
+entry:
+  %b = load i64, i64* %a, align 8
+  ret i64 %b
+}
+
+define i128 @test_load128(i128* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load128(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 100", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: %[[A:[^ ]*]] = bitcast i128* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 4)
+
+; CHECK: %[[G:[^ ]*]] = load i128, i128* %a, align 16
+; CHECK: ret i128 %[[G]]
+
+entry:
+  %b = load i128, i128* %a, align 16
+  ret i128 %b
+}
+
+define i40 @test_load40(i40* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load40(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
+; ABORT: call void @__hwasan_loadN(i64 %[[A]], i64 5)
+; RECOVER: call void @__hwasan_loadN_noabort(i64 %[[A]], i64 5)
+; CHECK: %[[B:[^ ]*]] = load i40, i40* %a
+; CHECK: ret i40 %[[B]]
+
+entry:
+  %b = load i40, i40* %a, align 4
+  ret i40 %b
+}
+
+define void @test_store8(i8* %a, i8 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store8(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 112", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %a, i32 16)
+
+; CHECK: store i8 %b, i8* %a, align 4
+; CHECK: ret void
+
+entry:
+  store i8 %b, i8* %a, align 4
+  ret void
+}
+
+define void @test_store16(i16* %a, i16 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store16(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 113", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: %[[A:[^ ]*]] = bitcast i16* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 17)
+
+; CHECK: store i16 %b, i16* %a, align 4
+; CHECK: ret void
+
+entry:
+  store i16 %b, i16* %a, align 4
+  ret void
+}
+
+define void @test_store32(i32* %a, i32 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store32(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 114", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: %[[A:[^ ]*]] = bitcast i32* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 18)
+
+; CHECK: store i32 %b, i32* %a, align 4
+; CHECK: ret void
+
+entry:
+  store i32 %b, i32* %a, align 4
+  ret void
+}
+
+define void @test_store64(i64* %a, i64 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store64(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 115", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: %[[A:[^ ]*]] = bitcast i64* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 19)
+
+; CHECK: store i64 %b, i64* %a, align 8
+; CHECK: ret void
+
+entry:
+  store i64 %b, i64* %a, align 8
+  ret void
+}
+
+define void @test_store128(i128* %a, i128 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store128(
+; RECOVER: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
+; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56
+; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8
+; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935
+; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4
+; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, i8* %.hwasan.shadow, i64 %4
+; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to i8*
+; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, i8* %[[E]]
+; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]]
+; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}}
+
+; RECOVER: call void asm sideeffect alignstack "ebreak\0Aaddiw x0, x0, 116", "{x10}"(i64 %[[A]])
+; RECOVER: br label
+
+; ABORT: %[[A:[^ ]*]] = bitcast i128* %a to i8*
+; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(i8* %.hwasan.shadow, i8* %[[A]], i32 20)
+
+; CHECK: store i128 %b, i128* %a, align 16
+; CHECK: ret void
+
+entry:
+  store i128 %b, i128* %a, align 16
+  ret void
+}
+
+define void @test_store40(i40* %a, i40 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store40(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
+; ABORT: call void @__hwasan_storeN(i64 %[[A]], i64 5)
+; RECOVER: call void @__hwasan_storeN_noabort(i64 %[[A]], i64 5)
+; CHECK: store i40 %b, i40* %a
+; CHECK: ret void
+
+entry:
+  store i40 %b, i40* %a, align 4
+  ret void
+}
+
+define void @test_store_unaligned(i64* %a, i64 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store_unaligned(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
+; ABORT: call void @__hwasan_storeN(i64 %[[A]], i64 8)
+; RECOVER: call void @__hwasan_storeN_noabort(i64 %[[A]], i64 8)
+; CHECK: store i64 %b, i64* %a, align 4
+; CHECK: ret void
+
+entry:
+  store i64 %b, i64* %a, align 4
+  ret void
+}
+
+define i8 @test_load_noattr(i8* %a) {
+; CHECK-LABEL: @test_load_noattr(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %[[B:[^ ]*]] = load i8, i8* %a
+; CHECK-NEXT: ret i8 %[[B]]
+
+entry:
+  %b = load i8, i8* %a, align 4
+  ret i8 %b
+}
+
+define i8 @test_load_notmyattr(i8* %a) sanitize_address {
+; CHECK-LABEL: @test_load_notmyattr(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %[[B:[^ ]*]] = load i8, i8* %a
+; CHECK-NEXT: ret i8 %[[B]]
+
+entry:
+  %b = load i8, i8* %a, align 4
+  ret i8 %b
+}
+
+define i8 @test_load_addrspace(i8 addrspace(256)* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load_addrspace(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %[[B:[^ ]*]] = load i8, i8 addrspace(256)* %a
+; CHECK-NEXT: ret i8 %[[B]]
+
+entry:
+  %b = load i8, i8 addrspace(256)* %a, align 4
+  ret i8 %b
+}
+
+; CHECK: declare void @__hwasan_init()
+
+; CHECK:      define internal void @hwasan.module_ctor() #[[#ATTR:]] comdat {
+; CHECK-NEXT:   call void @__hwasan_init()
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }
+
+; CHECK:      attributes #[[#ATTR]] = { nounwind }

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/exception-lifetime.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/exception-lifetime.ll
new file mode 100644
index 0000000000000..7007bbaefc196
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/exception-lifetime.ll
@@ -0,0 +1,60 @@
+; Test allocas with multiple lifetime ends, as frequently seen for exception
+; handling.
+;
+; RUN: opt -passes=hwasan -hwasan-use-after-scope -S -o - %s | FileCheck %s --check-prefix=CHECK
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+declare void @mayFail(i32* %x) sanitize_hwaddress
+declare void @onExcept(i32* %x) sanitize_hwaddress
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind
+declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) nounwind
+declare i32 @__gxx_personality_v0(...)
+
+define void @test() sanitize_hwaddress personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+entry:
+  %x = alloca i32, align 8
+  %exn.slot = alloca i8*, align 8
+  %ehselector.slot = alloca i32, align 4
+  %0 = bitcast i32* %x to i8*
+  call void @llvm.lifetime.start.p0i8(i64 8, i8* %0)
+  invoke void @mayFail(i32* %x) to label %invoke.cont unwind label %lpad
+; CHECK: [[CAST:%.*]] = bitcast { i32, [12 x i8] }* %x to i32*
+; CHECK: [[TMP1:%.*]] = bitcast i32* {{.*}}[[CAST]] to i8*
+
+invoke.cont:                                      ; preds = %entry
+; CHECK: invoke.cont:
+; CHECK:  call void @llvm.memset.p0i8.i64(i8* align 1 %{{.*}}, i8 0, i64 1, i1 false)
+; CHECK:  call void @llvm.lifetime.end.p0i8(i64 16, i8* {{.*}}[[TMP1]])
+; CHECK:  ret void
+
+  %1 = bitcast i32* %x to i8*
+  call void @llvm.lifetime.end.p0i8(i64 8, i8* %1)
+  ret void
+
+lpad:                                             ; preds = %entry
+; CHECK: lpad
+; CHECK:  call void @llvm.memset.p0i8.i64(i8* align 1 %{{.*}}, i8 0, i64 1, i1 false)
+; CHECK:  call void @llvm.lifetime.end.p0i8(i64 16, i8* {{.*}}[[TMP1]])
+; CHECK:  br label %eh.resume
+
+  %2 = landingpad { i8*, i32 }
+  cleanup
+  %3 = extractvalue { i8*, i32 } %2, 0
+  store i8* %3, i8** %exn.slot, align 8
+  %4 = extractvalue { i8*, i32 } %2, 1
+  store i32 %4, i32* %ehselector.slot, align 4
+  call void @onExcept(i32* %x) #18
+  %5 = bitcast i32* %x to i8*
+  call void @llvm.lifetime.end.p0i8(i64 8, i8* %5)
+  br label %eh.resume
+
+eh.resume:                                        ; preds = %lpad
+  %exn = load i8*, i8** %exn.slot, align 8
+  %sel = load i32, i32* %ehselector.slot, align 4
+  %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0
+  %lpad.val1 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1
+  resume { i8*, i32 } %lpad.val1
+}

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/stack-safety-analysis.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/stack-safety-analysis.ll
new file mode 100644
index 0000000000000..8a5c119224943
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/stack-safety-analysis.ll
@@ -0,0 +1,315 @@
+; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY,CHECK
+; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY,CHECK
+; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY,CHECK
+; RUN: opt -passes=hwasan -hwasan-instrument-stack=0 -hwasan-instrument-with-calls -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSTACK,CHECK
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+; Check a safe alloca to ensure it does not get a tag.
+define i32 @test_simple(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_simple
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca i8, align 4
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  ret i32 0
+}
+
+; Check a non-safe alloca to ensure it gets a tag.
+define i32 @test_use(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_use
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca i8, align 4
+  call void @use(i8* nonnull %buf.sroa.0)
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  ret i32 0
+}
+
+; Check an alloca with in range GEP to ensure it does not get a tag or check.
+define i32 @test_in_range(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_in_range
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 0
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %ptr)
+  store volatile i8 0, i8* %ptr, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %ptr)
+  ret i32 0
+}
+
+; Check an alloca with in range GEP to ensure it does not get a tag or check.
+define i32 @test_in_range2(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_in_range2
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %x)
+  store volatile i8 0, i8* %ptr, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %x)
+  ret i32 0
+}
+
+define i32 @test_in_range3(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_in_range3
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_memset
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_memset
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_memset
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  call void @llvm.memset.p0i8.i32(i8* %ptr, i8 0, i32 1, i1 true)
+  ret i32 0
+}
+
+define i32 @test_in_range4(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_in_range4
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_memmove
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_memmove
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_memmove
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %ptr, i8* %ptr, i32 1, i1 true)
+  ret i32 0
+}
+
+define i32 @test_in_range5(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_in_range5
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_memmove
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_memmove
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_memmove
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  %buf.sroa.1 = alloca [10 x i8], align 4
+  %ptr1 = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %y = bitcast [10 x i8]* %buf.sroa.1 to i8*
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %ptr, i8* %ptr1, i32 1, i1 true)
+  ret i32 0
+}
+
+; Check an alloca with out of range GEP to ensure it gets a tag and check.
+define i32 @test_out_of_range(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_out_of_range
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 10
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %x)
+  store volatile i8 0, i8* %ptr, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %x)
+  ret i32 0
+}
+
+define i32 @test_out_of_range3(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_out_of_range3
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_memset
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_memset
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_memset
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  call void @llvm.memset.p0i8.i32(i8* %ptr, i8 0, i32 2, i1 true)
+  ret i32 0
+}
+
+define i32 @test_out_of_range4(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_out_of_range4
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_memmove
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_memmove
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_memmove
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %ptr, i8* %ptr, i32 2, i1 true)
+  ret i32 0
+}
+
+define i32 @test_out_of_range5(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_out_of_range5
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_memmove
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_memmove
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_memmove
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  %buf.sroa.1 = alloca [10 x i8], align 4
+  %ptr1 = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %y = bitcast [10 x i8]* %buf.sroa.1 to i8*
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %x)
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %x)
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %y)
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %ptr, i8* %ptr1, i32 1, i1 true)
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %y)
+  ret i32 0
+}
+
+; Check an alloca with potentially out of range GEP to ensure it gets a tag and
+; check.
+define i32 @test_potentially_out_of_range(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_potentially_out_of_range
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %off = call i32 @getoffset()
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 %off
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %ptr)
+  store volatile i8 0, i8* %ptr, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %ptr)
+  ret i32 0
+}
+
+define i32 @test_potentially_out_of_range2(i8* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_potentially_out_of_range2
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_memmove
+  ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_memmove
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK: call {{.*}}__hwasan_memmove
+  %buf.sroa.0 = alloca [10 x i8], align 4
+  %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 9
+  %x = bitcast [10 x i8]* %buf.sroa.0 to i8*
+  call void @llvm.memmove.p0i8.p0i8.i32(i8* %ptr, i8* %a, i32 1, i1 true)
+  ret i32 0
+}
+; Check an alloca with potentially out of range GEP to ensure it gets a tag and
+; check.
+define i32 @test_unclear(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_unclear
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca i8, align 4
+  %ptr = call i8* @getptr(i8* %buf.sroa.0)
+  call void @llvm.lifetime.start.p0i8(i64 10, i8* nonnull %ptr)
+  store volatile i8 0, i8* %ptr, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 10, i8* nonnull %ptr)
+  ret i32 0
+}
+
+define i32 @test_select(i8* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_select
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK: call {{.*}}__hwasan_store
+  %x = call i8* @getptr(i8* %a)
+  %buf.sroa.0 = alloca i8, align 4
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  %c = call i1 @cond()
+  %ptr = select i1 %c, i8* %x, i8* %buf.sroa.0
+  store volatile i8 0, i8* %ptr, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  ret i32 0
+}
+
+; Check whether we see through the returns attribute of functions.
+define i32 @test_retptr(i32* %a) sanitize_hwaddress {
+entry:
+  ; CHECK-LABEL: @test_retptr
+  ; NOSAFETY: call {{.*}}__hwasan_generate_tag
+  ; NOSAFETY: call {{.*}}__hwasan_store
+  ; SAFETY: call {{.*}}__hwasan_generate_tag
+  ; SAFETY-NOT: call {{.*}}__hwasan_store
+  ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag
+  ; NOSTACK-NOT: call {{.*}}__hwasan_store
+  %buf.sroa.0 = alloca i8, align 4
+  call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  %ptr = call i8* @retptr(i8* %buf.sroa.0)
+  store volatile i8 0, i8* %ptr, align 4, !tbaa !8
+  call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
+  ret i32 0
+}
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
+
+; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
+
+declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i1)
+declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1)
+declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i1)
+
+declare i1 @cond()
+declare void @use(i8* nocapture)
+declare i32 @getoffset()
+declare i8* @getptr(i8* nocapture)
+declare i8* @retptr(i8* returned)
+
+!8 = !{!9, !9, i64 0}
+!9 = !{!"omnipotent char", !10, i64 0}
+!10 = !{!"Simple C/C++ TBAA"}

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/use-after-scope-setjmp.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/use-after-scope-setjmp.ll
new file mode 100644
index 0000000000000..7058fb6469ffa
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/use-after-scope-setjmp.ll
@@ -0,0 +1,43 @@
+; RUN: opt -passes=hwasan -hwasan-use-stack-safety=0 -hwasan-use-after-scope -S < %s | FileCheck %s
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+ at stackbuf = dso_local local_unnamed_addr global i8* null, align 8
+ at jbuf = dso_local global [32 x i64] zeroinitializer, align 8
+
+declare void @may_jump()
+
+define dso_local noundef i1 @_Z6targetv() sanitize_hwaddress {
+entry:
+  %buf = alloca [4096 x i8], align 1
+  %call = call i32 @setjmp(i64* noundef getelementptr inbounds ([32 x i64], [32 x i64]* @jbuf, i64 0, i64 0))
+  switch i32 %call, label %while.body [
+    i32 1, label %return
+    i32 2, label %sw.bb1
+  ]
+
+sw.bb1:                                           ; preds = %entry
+  br label %return
+
+while.body:                                       ; preds = %entry
+  %0 = getelementptr inbounds [4096 x i8], [4096 x i8]* %buf, i64 0, i64 0
+  call void @llvm.lifetime.start.p0i8(i64 4096, i8* nonnull %0) #10
+  store i8* %0, i8** @stackbuf, align 8
+  ; may_jump may call longjmp, going back to the switch (and then the return),
+  ; bypassing the lifetime.end. This is why we need to untag on the return,
+  ; rather than the lifetime.end.
+  call void @may_jump()
+  call void @llvm.lifetime.end.p0i8(i64 4096, i8* nonnull %0) #10
+  br label %return
+
+; CHECK-LABEL: return:
+; CHECK: void @llvm.memset.p0i8.i64({{.*}}, i8 0, i64 256, i1 false)
+return:                                           ; preds = %entry, %while.body, %sw.bb1
+  %retval.0 = phi i1 [ true, %while.body ], [ true, %sw.bb1 ], [ false, %entry ]
+  ret i1 %retval.0
+}
+
+declare i32 @setjmp(i64* noundef) returns_twice
+
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
+declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)

diff  --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/with-calls.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/with-calls.ll
new file mode 100644
index 0000000000000..fb4cc0a859c09
--- /dev/null
+++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/with-calls.ll
@@ -0,0 +1,203 @@
+; Test basic address sanitizer instrumentation.
+;
+; RUN: opt < %s -passes=hwasan -hwasan-instrument-with-calls -S | FileCheck %s --check-prefixes=CHECK,ABORT
+; RUN: opt < %s -passes=hwasan -hwasan-instrument-with-calls -hwasan-recover=1 -S | FileCheck %s --check-prefixes=CHECK,RECOVER
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux"
+
+define i8 @test_load8(i8* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load8(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
+; ABORT: call void @__hwasan_load1(i64 %[[A]])
+; RECOVER: call void @__hwasan_load1_noabort(i64 %[[A]])
+; CHECK: %[[B:[^ ]*]] = load i8, i8* %a
+; CHECK: ret i8 %[[B]]
+
+entry:
+  %b = load i8, i8* %a, align 4
+  ret i8 %b
+}
+
+define i16 @test_load16(i16* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load16(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
+; ABORT: call void @__hwasan_load2(i64 %[[A]])
+; RECOVER: call void @__hwasan_load2_noabort(i64 %[[A]])
+; CHECK: %[[B:[^ ]*]] = load i16, i16* %a
+; CHECK: ret i16 %[[B]]
+
+entry:
+  %b = load i16, i16* %a, align 4
+  ret i16 %b
+}
+
+define i32 @test_load32(i32* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load32(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
+; ABORT: call void @__hwasan_load4(i64 %[[A]])
+; RECOVER: call void @__hwasan_load4_noabort(i64 %[[A]])
+; CHECK: %[[B:[^ ]*]] = load i32, i32* %a
+; CHECK: ret i32 %[[B]]
+
+entry:
+  %b = load i32, i32* %a, align 4
+  ret i32 %b
+}
+
+define i64 @test_load64(i64* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load64(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
+; ABORT: call void @__hwasan_load8(i64 %[[A]])
+; RECOVER: call void @__hwasan_load8_noabort(i64 %[[A]])
+; CHECK: %[[B:[^ ]*]] = load i64, i64* %a
+; CHECK: ret i64 %[[B]]
+
+entry:
+  %b = load i64, i64* %a, align 8
+  ret i64 %b
+}
+
+define i128 @test_load128(i128* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load128(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
+; ABORT: call void @__hwasan_load16(i64 %[[A]])
+; RECOVER: call void @__hwasan_load16_noabort(i64 %[[A]])
+; CHECK: %[[B:[^ ]*]] = load i128, i128* %a
+; CHECK: ret i128 %[[B]]
+
+entry:
+  %b = load i128, i128* %a, align 16
+  ret i128 %b
+}
+
+define i40 @test_load40(i40* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load40(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
+; ABORT: call void @__hwasan_loadN(i64 %[[A]], i64 5)
+; RECOVER: call void @__hwasan_loadN_noabort(i64 %[[A]], i64 5)
+; CHECK: %[[B:[^ ]*]] = load i40, i40* %a
+; CHECK: ret i40 %[[B]]
+
+entry:
+  %b = load i40, i40* %a, align 4
+  ret i40 %b
+}
+
+define void @test_store8(i8* %a, i8 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store8(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i8* %a to i64
+; ABORT: call void @__hwasan_store1(i64 %[[A]])
+; RECOVER: call void @__hwasan_store1_noabort(i64 %[[A]])
+; CHECK: store i8 %b, i8* %a
+; CHECK: ret void
+
+entry:
+  store i8 %b, i8* %a, align 4
+  ret void
+}
+
+define void @test_store16(i16* %a, i16 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store16(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i16* %a to i64
+; ABORT: call void @__hwasan_store2(i64 %[[A]])
+; RECOVER: call void @__hwasan_store2_noabort(i64 %[[A]])
+; CHECK: store i16 %b, i16* %a
+; CHECK: ret void
+
+entry:
+  store i16 %b, i16* %a, align 4
+  ret void
+}
+
+define void @test_store32(i32* %a, i32 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store32(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i32* %a to i64
+; ABORT: call void @__hwasan_store4(i64 %[[A]])
+; RECOVER: call void @__hwasan_store4_noabort(i64 %[[A]])
+; CHECK: store i32 %b, i32* %a
+; CHECK: ret void
+
+entry:
+  store i32 %b, i32* %a, align 4
+  ret void
+}
+
+define void @test_store64(i64* %a, i64 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store64(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i64* %a to i64
+; ABORT: call void @__hwasan_store8(i64 %[[A]])
+; RECOVER: call void @__hwasan_store8_noabort(i64 %[[A]])
+; CHECK: store i64 %b, i64* %a
+; CHECK: ret void
+
+entry:
+  store i64 %b, i64* %a, align 8
+  ret void
+}
+
+define void @test_store128(i128* %a, i128 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store128(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i128* %a to i64
+; ABORT: call void @__hwasan_store16(i64 %[[A]])
+; RECOVER: call void @__hwasan_store16_noabort(i64 %[[A]])
+; CHECK: store i128 %b, i128* %a
+; CHECK: ret void
+
+entry:
+  store i128 %b, i128* %a, align 16
+  ret void
+}
+
+define void @test_store40(i40* %a, i40 %b) sanitize_hwaddress {
+; CHECK-LABEL: @test_store40(
+; CHECK: %[[A:[^ ]*]] = ptrtoint i40* %a to i64
+; ABORT: call void @__hwasan_storeN(i64 %[[A]], i64 5)
+; RECOVER: call void @__hwasan_storeN_noabort(i64 %[[A]], i64 5)
+; CHECK: store i40 %b, i40* %a
+; CHECK: ret void
+
+entry:
+  store i40 %b, i40* %a, align 4
+  ret void
+}
+
+define i8 @test_load_noattr(i8* %a) {
+; CHECK-LABEL: @test_load_noattr(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %[[B:[^ ]*]] = load i8, i8* %a
+; CHECK-NEXT: ret i8 %[[B]]
+
+entry:
+  %b = load i8, i8* %a, align 4
+  ret i8 %b
+}
+
+define i8 @test_load_notmyattr(i8* %a) sanitize_address {
+; CHECK-LABEL: @test_load_notmyattr(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %[[B:[^ ]*]] = load i8, i8* %a
+; CHECK-NEXT: ret i8 %[[B]]
+
+entry:
+  %b = load i8, i8* %a, align 4
+  ret i8 %b
+}
+
+define i8 @test_load_addrspace(i8 addrspace(256)* %a) sanitize_hwaddress {
+; CHECK-LABEL: @test_load_addrspace(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %[[B:[^ ]*]] = load i8, i8 addrspace(256)* %a
+; CHECK-NEXT: ret i8 %[[B]]
+
+entry:
+  %b = load i8, i8 addrspace(256)* %a, align 4
+  ret i8 %b
+}
+
+; CHECK: declare void @__hwasan_init()
+
+; CHECK:      define internal void @hwasan.module_ctor() #[[#]] comdat {
+; CHECK-NEXT:   call void @__hwasan_init()
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: }


        


More information about the llvm-commits mailing list