Index: llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -111,6 +111,13 @@ static const uint64_t kPS4CPU_ShadowOffset64 = 1ULL << 40; static const uint64_t kWindowsShadowOffset32 = 3ULL << 28; +static const uint64_t kMyriadShadowScale = 5; +static const uint64_t kMyriadBaseMemOffset32 = 0x80000000ULL; +static const uint64_t kMyriadShadowOffset32 = 0x9f000000ULL; +static const uint64_t kMyriadTagShift = 29; +static const uint64_t kMyriadDDRTag = 4; +static const uint64_t kMyriadCacheBitMask32 = 0x40000000ULL; + // The shadow memory space is dynamically allocated. static const uint64_t kWindowsShadowOffset64 = kDynamicShadowSentinel; @@ -493,10 +500,11 @@ bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64; bool IsWindows = TargetTriple.isOSWindows(); bool IsFuchsia = TargetTriple.isOSFuchsia(); + bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad; ShadowMapping Mapping; - Mapping.Scale = kDefaultShadowScale; + Mapping.Scale = IsMyriad ? kMyriadShadowScale : kDefaultShadowScale; if (ClMappingScale.getNumOccurrences() > 0) { Mapping.Scale = ClMappingScale; } @@ -513,6 +521,10 @@ Mapping.Offset = IsX86 ? kIOSSimShadowOffset32 : kIOSShadowOffset32; else if (IsWindows) Mapping.Offset = kWindowsShadowOffset32; + else if (IsMyriad) { + Mapping.Offset = kMyriadShadowOffset32 - + (kMyriadBaseMemOffset32 >> kMyriadShadowScale); + } else Mapping.Offset = kDefaultShadowOffset32; } else { // LongSize == 64 @@ -1492,6 +1504,8 @@ uint32_t TypeSize, bool IsWrite, Value *SizeArgument, bool UseCalls, uint32_t Exp) { + bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad; + IRBuilder<> IRB(InsertBefore); Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize); @@ -1506,6 +1520,23 @@ return; } + if (IsMyriad) { + // Strip the cache bit and do range check. + // AddrLong &= ~kMyriadCacheBitMask32 + AddrLong = IRB.CreateAnd(AddrLong, ~kMyriadCacheBitMask32); + // Tag = AddrLong >> kMyriadTagShift + Value *Tag = IRB.CreateLShr(AddrLong, kMyriadTagShift); + // Tag == kMyriadDDRTag + Value *TagCheck = + IRB.CreateICmpEQ(Tag, ConstantInt::get(IntptrTy, kMyriadDDRTag)); + + TerminatorInst *TagCheckTerm = SplitBlockAndInsertIfThen( + TagCheck, InsertBefore, false, MDBuilder(*C).createBranchWeights(1, 100000)); + assert(cast(TagCheckTerm)->isUnconditional()); + IRB.SetInsertPoint(TagCheckTerm); + InsertBefore = TagCheckTerm; + } + Type *ShadowTy = IntegerType::get(*C, std::max(8U, TypeSize >> Mapping.Scale)); Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); Index: llvm/test/Instrumentation/AddressSanitizer/basic-myriad.ll =================================================================== --- /dev/null +++ llvm/test/Instrumentation/AddressSanitizer/basic-myriad.ll @@ -0,0 +1,84 @@ +; Test basic address sanitizer instrumentation for Myriad. +; +; RUN: opt -asan -asan-module -S < %s | FileCheck %s + +target triple = "sparc-myriad-rtems" +target datalayout = "E-m:e-p:32:32-i64:64-f128:64-n32-S64" +; CHECK: @llvm.global_ctors = {{.*}}@asan.module_ctor + +define i32 @test_load(i32* %a) sanitize_address { +; CHECK-LABEL: @test_load +; CHECK-NOT: load +; CHECK: ptrtoint i32* %a to i32 +; CHECK: %[[LOAD_ADDR:[^ ]*]] = and i32 %{{.*}}, -1073741825 +; CHECK: lshr i32 %{{.*}}, 29 +; CHECK: icmp eq i32 %{{.*}}, 4 +; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}!prof ![[PROF:[0-9]+]] +; +; This block checks whether the shadow byte is 0. +; CHECK: lshr i32 %[[LOAD_ADDR]], 5 +; CHECK: add i32 %{{.*}}, -1694498816 +; CHECK: %[[LOAD_SHADOW_PTR:[^ ]*]] = inttoptr +; CHECK: %[[LOAD_SHADOW:[^ ]*]] = load i8, i8* %[[LOAD_SHADOW_PTR]] +; CHECK: icmp ne i8 +; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}!prof ![[PROF:[0-9]+]] +; +; This block refines the shadow test. +; CHECK: and i32 %[[LOAD_ADDR]], 31 +; CHECK: add i32 %{{.*}}, 3 +; CHECK: trunc i32 %{{.*}} to i8 +; CHECK: icmp sge i8 %{{.*}}, %[[LOAD_SHADOW]] +; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} +; +; The crash block reports the error. +; CHECK: call void @__asan_report_load4(i32 %[[LOAD_ADDR]]) +; CHECK: unreachable +; +; The actual load. +; CHECK: %tmp1 = load i32, i32* %a +; CHECK: ret i32 %tmp1 + +entry: + %tmp1 = load i32, i32* %a, align 4 + ret i32 %tmp1 +} + +define void @test_store(i32* %a) sanitize_address { +; CHECK-LABEL: @test_store +; CHECK-NOT: store +; CHECK: ptrtoint i32* %a to i32 +; CHECK: %[[STORE_ADDR:[^ ]*]] = and i32 %{{.*}}, -1073741825 +; CHECK: lshr i32 %{{.*}}, 29 +; CHECK: icmp eq i32 %{{.*}}, 4 +; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}!prof ![[PROF:[0-9]+]] +; +; This block checks whether the shadow byte is 0. +; CHECK: lshr i32 %[[STORE_ADDR]], 5 +; CHECK: add i32 %{{.*}}, -1694498816 +; CHECK: %[[STORE_SHADOW_PTR:[^ ]*]] = inttoptr +; CHECK: %[[STORE_SHADOW:[^ ]*]] = load i8, i8* %[[STORE_SHADOW_PTR]] +; CHECK: icmp ne i8 +; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} +; +; This block refines the shadow test. +; CHECK: and i32 %[[STORE_ADDR]], 31 +; CHECK: add i32 %{{.*}}, 3 +; CHECK: trunc i32 %{{.*}} to i8 +; CHECK: icmp sge i8 %{{.*}}, %[[STORE_SHADOW]] +; CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}} +; +; The crash block reports the error. +; CHECK: call void @__asan_report_store4(i32 %[[STORE_ADDR]]) +; CHECK: unreachable +; The actual store. +; CHECK: store i32 42, i32* %a +; CHECK: ret void +; + +entry: + store i32 42, i32* %a, align 4 + ret void +} + +; CHECK: define internal void @asan.module_ctor() +; CHECK: call void @__asan_init()