diff --git a/llvm/lib/Target/X86/X86AsmPrinter.h b/llvm/lib/Target/X86/X86AsmPrinter.h
--- a/llvm/lib/Target/X86/X86AsmPrinter.h
+++ b/llvm/lib/Target/X86/X86AsmPrinter.h
@@ -100,6 +100,20 @@
// Address sanitizer specific lowering for X86.
void LowerASAN_CHECK_MEMACCESS(const MachineInstr &MI);
+ void emitAsanMemaccessSymbols(Module &M);
+ void emitAsanMemaccessPartial(Module &M, unsigned Reg,
+ const ASanAccessInfo &AccessInfo,
+ MCSubtargetInfo &STI);
+ void emitAsanMemaccessFull(Module &M, unsigned Reg,
+ const ASanAccessInfo &AccessInfo,
+ MCSubtargetInfo &STI);
+ void emitAsanReportError(Module &M, unsigned Reg,
+ const ASanAccessInfo &AccessInfo,
+ MCSubtargetInfo &STI);
+
+ typedef std::tuple
+ AsanMemaccessTuple;
+ std::map AsanMemaccessSymbols;
// Choose between emitting .seh_ directives and .cv_fpo_ directives.
void EmitSEHInstruction(const MachineInstr *MI);
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -754,6 +754,8 @@
void X86AsmPrinter::emitEndOfAsmFile(Module &M) {
const Triple &TT = TM.getTargetTriple();
+ emitAsanMemaccessSymbols(M);
+
if (TT.isOSBinFormatMachO()) {
// Mach-O uses non-lazy symbol stubs to encode per-TU information into
// global table for symbol lookup.
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -48,7 +48,6 @@
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
-#include
using namespace llvm;
@@ -1337,29 +1336,235 @@
return;
}
- const auto &Reg = MI.getOperand(0).getReg();
+ unsigned Reg = MI.getOperand(0).getReg().id();
ASanAccessInfo AccessInfo(MI.getOperand(1).getImm());
+ MCSymbol *&Sym =
+ AsanMemaccessSymbols[AsanMemaccessTuple(Reg, AccessInfo.Packed)];
+ if (!Sym) {
+ std::string Name = AccessInfo.IsWrite ? "store" : "load";
+ std::string SymName = "__asan_check_" + Name +
+ utostr(1ULL << AccessInfo.AccessSizeIndex) + "_rn" +
+ utostr(Reg);
+ Sym = OutContext.getOrCreateSymbol(SymName);
+ }
+
+ EmitAndCountInstruction(
+ MCInstBuilder(X86::CALL64pcrel32)
+ .addExpr(MCSymbolRefExpr::create(Sym, OutContext)));
+}
+
+void X86AsmPrinter::emitAsanMemaccessPartial(Module &M, unsigned Reg,
+ const ASanAccessInfo &AccessInfo,
+ MCSubtargetInfo &STI) {
+ assert(AccessInfo.AccessSizeIndex == 0 || AccessInfo.AccessSizeIndex == 1 ||
+ AccessInfo.AccessSizeIndex == 2);
+ assert(Reg != X86::R10);
+ assert(Reg != X86::R11);
+
+ uint64_t ShadowBase;
+ int MappingScale;
+ bool OrShadowOffset;
+ getAddressSanitizerParams(
+ Triple(M.getTargetTriple()), M.getDataLayout().getPointerSizeInBits(),
+ AccessInfo.CompileKernel, &ShadowBase, &MappingScale, &OrShadowOffset);
+
+ OutStreamer->emitInstruction(MCInstBuilder(X86::MOV64rr)
+ .addReg(X86::R10)
+ .addReg(X86::NoRegister + Reg),
+ STI);
+ OutStreamer->emitInstruction(MCInstBuilder(X86::SHR64ri)
+ .addReg(X86::R10)
+ .addReg(X86::R10)
+ .addImm(MappingScale),
+ STI);
+ if (OrShadowOffset) {
+ OutStreamer->emitInstruction(MCInstBuilder(X86::OR64ri32)
+ .addReg(X86::R10)
+ .addReg(X86::R10)
+ .addImm(ShadowBase),
+ STI);
+ OutStreamer->emitInstruction(MCInstBuilder(X86::MOV8rm)
+ .addReg(X86::R10B)
+ .addReg(X86::R10)
+ .addImm(1)
+ .addReg(X86::NoRegister)
+ .addImm(0)
+ .addReg(X86::NoRegister),
+ STI);
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::TEST8rr).addReg(X86::R10B).addReg(X86::R10B), STI);
+ } else {
+ OutStreamer->emitInstruction(MCInstBuilder(X86::MOVSX32rm8)
+ .addReg(X86::R10D)
+ .addReg(X86::R10)
+ .addImm(1)
+ .addReg(X86::NoRegister)
+ .addImm(ShadowBase)
+ .addReg(X86::NoRegister),
+ STI);
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::TEST32rr).addReg(X86::R10D).addReg(X86::R10D), STI);
+ }
+ MCSymbol *AdditionalCheck = OutContext.createTempSymbol();
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::JCC_1)
+ .addExpr(MCSymbolRefExpr::create(AdditionalCheck, OutContext))
+ .addImm(X86::COND_NE),
+ STI);
+ MCSymbol *ReturnSym = OutContext.createTempSymbol();
+ OutStreamer->emitLabel(ReturnSym);
+ OutStreamer->emitInstruction(MCInstBuilder(getRetOpcode(*Subtarget)), STI);
+
+ // Shadow byte is non-zero so we need to perform additional checks.
+ OutStreamer->emitLabel(AdditionalCheck);
+ OutStreamer->emitInstruction(MCInstBuilder(X86::MOV64rr)
+ .addReg(X86::R11)
+ .addReg(X86::NoRegister + Reg),
+ STI);
+ const size_t Granularity = 1ULL << MappingScale;
+ OutStreamer->emitInstruction(MCInstBuilder(X86::AND32ri8)
+ .addReg(X86::NoRegister)
+ .addReg(X86::R11D)
+ .addImm(Granularity - 1),
+ STI);
+ if (AccessInfo.AccessSizeIndex == 1) {
+ OutStreamer->emitInstruction(MCInstBuilder(X86::ADD32ri8)
+ .addReg(X86::NoRegister)
+ .addReg(X86::R11D)
+ .addImm(1),
+ STI);
+ } else if (AccessInfo.AccessSizeIndex == 2) {
+ OutStreamer->emitInstruction(MCInstBuilder(X86::ADD32ri8)
+ .addReg(X86::NoRegister)
+ .addReg(X86::R11D)
+ .addImm(3),
+ STI);
+ }
+
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::CMP32rr).addReg(X86::R11D).addReg(X86::R10D).addImm(1),
+ STI);
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::JCC_1)
+ .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext))
+ .addImm(X86::COND_L),
+ STI);
+
+ emitAsanReportError(M, Reg, AccessInfo, STI);
+}
+
+void X86AsmPrinter::emitAsanMemaccessFull(Module &M, unsigned Reg,
+ const ASanAccessInfo &AccessInfo,
+ MCSubtargetInfo &STI) {
+ assert(AccessInfo.AccessSizeIndex == 3 || AccessInfo.AccessSizeIndex == 4);
+ assert(Reg != X86::R10);
+ assert(Reg != X86::R11);
+
uint64_t ShadowBase;
int MappingScale;
bool OrShadowOffset;
- getAddressSanitizerParams(Triple(TM.getTargetTriple()), 64,
- AccessInfo.CompileKernel, &ShadowBase,
- &MappingScale, &OrShadowOffset);
+ getAddressSanitizerParams(
+ Triple(M.getTargetTriple()), M.getDataLayout().getPointerSizeInBits(),
+ AccessInfo.CompileKernel, &ShadowBase, &MappingScale, &OrShadowOffset);
+
+ OutStreamer->emitInstruction(MCInstBuilder(X86::MOV64rr)
+ .addReg(X86::R10)
+ .addReg(X86::NoRegister + Reg),
+ STI);
+ OutStreamer->emitInstruction(MCInstBuilder(X86::SHR64ri)
+ .addReg(X86::R10)
+ .addReg(X86::R10)
+ .addImm(MappingScale),
+ STI);
+ if (OrShadowOffset) {
+ OutStreamer->emitInstruction(MCInstBuilder(X86::OR64ri32)
+ .addReg(X86::R10)
+ .addReg(X86::R10)
+ .addImm(ShadowBase),
+ STI);
+ auto OpCode = AccessInfo.AccessSizeIndex == 3 ? X86::CMP8mi : X86::CMP16mi8;
+ OutStreamer->emitInstruction(MCInstBuilder(OpCode)
+ .addReg(X86::R10)
+ .addImm(1)
+ .addReg(X86::NoRegister)
+ .addImm(0)
+ .addReg(X86::NoRegister)
+ .addImm(0),
+ STI);
+ } else {
+ auto OpCode = AccessInfo.AccessSizeIndex == 3 ? X86::CMP8mi : X86::CMP16mi8;
+ OutStreamer->emitInstruction(MCInstBuilder(OpCode)
+ .addReg(X86::R10)
+ .addImm(1)
+ .addReg(X86::NoRegister)
+ .addImm(ShadowBase)
+ .addReg(X86::NoRegister)
+ .addImm(0),
+ STI);
+ }
+ MCSymbol *ReportCode = OutContext.createTempSymbol();
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::JCC_1)
+ .addExpr(MCSymbolRefExpr::create(ReportCode, OutContext))
+ .addImm(X86::COND_NE),
+ STI);
+ MCSymbol *ReturnSym = OutContext.createTempSymbol();
+ OutStreamer->emitLabel(ReturnSym);
+ OutStreamer->emitInstruction(MCInstBuilder(getRetOpcode(*Subtarget)), STI);
+
+ OutStreamer->emitLabel(ReportCode);
+ emitAsanReportError(M, Reg, AccessInfo, STI);
+}
+void X86AsmPrinter::emitAsanReportError(Module &M, unsigned Reg,
+ const ASanAccessInfo &AccessInfo,
+ MCSubtargetInfo &STI) {
std::string Name = AccessInfo.IsWrite ? "store" : "load";
- std::string Op = OrShadowOffset ? "or" : "add";
- std::string SymName = "__asan_check_" + Name + "_" + Op + "_" +
- utostr(1ULL << AccessInfo.AccessSizeIndex) + "_" +
- TM.getMCRegisterInfo()->getName(Reg.asMCReg());
- if (OrShadowOffset)
- llvm_unreachable(
- "OrShadowOffset is not supported with optimized callbacks");
+ MCSymbol *ReportError = OutContext.getOrCreateSymbol(
+ "__asan_report_" + Name + utostr(1ULL << AccessInfo.AccessSizeIndex));
+ OutStreamer->emitInstruction(MCInstBuilder(X86::MOV64rr)
+ .addReg(X86::RDI)
+ .addReg(X86::NoRegister + Reg),
+ STI);
+ OutStreamer->emitInstruction(
+ MCInstBuilder(X86::JMP_4)
+ .addExpr(MCSymbolRefExpr::create(ReportError, MCSymbolRefExpr::VK_PLT,
+ OutContext)),
+ STI);
+}
- EmitAndCountInstruction(
- MCInstBuilder(X86::CALL64pcrel32)
- .addExpr(MCSymbolRefExpr::create(
- OutContext.getOrCreateSymbol(SymName), OutContext)));
+void X86AsmPrinter::emitAsanMemaccessSymbols(Module &M) {
+ if (AsanMemaccessSymbols.empty())
+ return;
+
+ const Triple &TT = TM.getTargetTriple();
+ assert(TT.isOSBinFormatELF());
+ std::unique_ptr STI(
+ TM.getTarget().createMCSubtargetInfo(TT.str(), "", ""));
+ assert(STI && "Unable to create subtarget info");
+
+ for (auto &P : AsanMemaccessSymbols) {
+ MCSymbol *Sym = P.second;
+ OutStreamer->SwitchSection(OutContext.getELFSection(
+ ".text.hot", ELF::SHT_PROGBITS,
+ ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),
+ /*IsComdat=*/true));
+
+ OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
+ OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
+ OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
+ OutStreamer->emitLabel(Sym);
+
+ unsigned Reg = std::get<0>(P.first);
+ ASanAccessInfo AccessInfo(std::get<1>(P.first));
+
+ if (AccessInfo.AccessSizeIndex < 3) {
+ emitAsanMemaccessPartial(M, Reg, AccessInfo, *STI);
+ } else {
+ emitAsanMemaccessFull(M, Reg, AccessInfo, *STI);
+ }
+ }
}
void X86AsmPrinter::LowerPATCHABLE_OP(const MachineInstr &MI,
diff --git a/llvm/test/CodeGen/X86/asan-check-memaccess-add.ll b/llvm/test/CodeGen/X86/asan-check-memaccess-add.ll
--- a/llvm/test/CodeGen/X86/asan-check-memaccess-add.ll
+++ b/llvm/test/CodeGen/X86/asan-check-memaccess-add.ll
@@ -5,8 +5,8 @@
define void @load1(i8* nocapture readonly %x) {
; CHECK: pushq %rax
; CHECK-NOT: push %rbp
-; CHECK: callq __asan_check_load_add_1_[[REG1:.*]]
-; CHECK: callq __asan_check_store_add_1_[[REG1]]
+; CHECK: callq __asan_check_load1_rn[[RN1:.*]]
+; CHECK: callq __asan_check_store1_rn[[RN1]]
; CHECK-NOT: pop %rbp
; CHECK: popq %rax
call void @llvm.asan.check.memaccess(i8* %x, i32 0)
@@ -17,8 +17,8 @@
define void @load2(i16* nocapture readonly %x) {
; CHECK: pushq %rax
; CHECK-NOT: push %rbp
-; CHECK: callq __asan_check_load_add_2_[[REG2:.*]]
-; CHECK: callq __asan_check_store_add_2_[[REG2]]
+; CHECK: callq __asan_check_load2_rn[[RN2:.*]]
+; CHECK: callq __asan_check_store2_rn[[RN2]]
; CHECK-NOT: pop %rbp
; CHECK: popq %rax
%1 = ptrtoint i16* %x to i64
@@ -31,8 +31,8 @@
define void @load4(i32* nocapture readonly %x) {
; CHECK: pushq %rax
; CHECK-NOT: push %rbp
-; CHECK: callq __asan_check_load_add_4_[[REG4:.*]]
-; CHECK: callq __asan_check_store_add_4_[[REG4]]
+; CHECK: callq __asan_check_load4_rn[[RN4:.*]]
+; CHECK: callq __asan_check_store4_rn[[RN4]]
; CHECK-NOT: pop %rbp
; CHECK: popq %rax
%1 = ptrtoint i32* %x to i64
@@ -44,8 +44,8 @@
define void @load8(i64* nocapture readonly %x) {
; CHECK: pushq %rax
; CHECK-NOT: push %rbp
-; CHECK: callq __asan_check_load_add_8_[[REG8:.*]]
-; CHECK: callq __asan_check_store_add_8_[[REG8]]
+; CHECK: callq __asan_check_load8_rn[[RN8:.*]]
+; CHECK: callq __asan_check_store8_rn[[RN8]]
; CHECK-NOT: pop %rbp
; CHECK: popq %rax
%1 = ptrtoint i64* %x to i64
@@ -58,8 +58,8 @@
define void @load16(i128* nocapture readonly %x) {
; CHECK: pushq %rax
; CHECK-NOT: push %rbp
-; CHECK: callq __asan_check_load_add_16_[[REG16:.*]]
-; CHECK: callq __asan_check_store_add_16_[[REG16]]
+; CHECK: callq __asan_check_load16_rn[[RN16:.*]]
+; CHECK: callq __asan_check_store16_rn[[RN16]]
; CHECK-NOT: pop %rbp
; CHECK: popq %rax
%1 = ptrtoint i128* %x to i64
@@ -69,4 +69,178 @@
ret void
}
+; CHECK: .type __asan_check_load1_rn[[RN1]],@function
+; CHECK-NEXT: .weak __asan_check_load1_rn[[RN1]]
+; CHECK-NEXT: .hidden __asan_check_load1_rn[[RN1]]
+; CHECK-NEXT: __asan_check_load1_rn[[RN1]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: movsbl 2147450880(%r10), %r10d
+; CHECK-NEXT: testl %r10d, %r10d
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load1
+
+; CHECK: .type __asan_check_load2_rn[[RN2]],@function
+; CHECK-NEXT: .weak __asan_check_load2_rn[[RN2]]
+; CHECK-NEXT: .hidden __asan_check_load2_rn[[RN2]]
+; CHECK-NEXT: __asan_check_load2_rn[[RN2]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: movsbl 2147450880(%r10), %r10d
+; CHECK-NEXT: testl %r10d, %r10d
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $1, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load2
+
+; CHECK: .type __asan_check_load4_rn[[RN4]],@function
+; CHECK-NEXT: .weak __asan_check_load4_rn[[RN4]]
+; CHECK-NEXT: .hidden __asan_check_load4_rn[[RN4]]
+; CHECK-NEXT: __asan_check_load4_rn[[RN4]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: movsbl 2147450880(%r10), %r10d
+; CHECK-NEXT: testl %r10d, %r10d
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $3, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load4
+
+; CHECK: .type __asan_check_load8_rn[[RN8]],@function
+; CHECK-NEXT: .weak __asan_check_load8_rn[[RN8]]
+; CHECK-NEXT: .hidden __asan_check_load8_rn[[RN8]]
+; CHECK-NEXT: __asan_check_load8_rn[[RN8]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: cmpb $0, 2147450880(%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load8
+
+; CHECK: .type __asan_check_load16_rn[[RN16]],@function
+; CHECK-NEXT: .weak __asan_check_load16_rn[[RN16]]
+; CHECK-NEXT: .hidden __asan_check_load16_rn[[RN16]]
+; CHECK-NEXT: __asan_check_load16_rn[[RN16]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: cmpw $0, 2147450880(%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load16
+
+; CHECK: .type __asan_check_store1_rn[[RN1]],@function
+; CHECK-NEXT: .weak __asan_check_store1_rn[[RN1]]
+; CHECK-NEXT: .hidden __asan_check_store1_rn[[RN1]]
+; CHECK-NEXT: __asan_check_store1_rn[[RN1]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: movsbl 2147450880(%r10), %r10d
+; CHECK-NEXT: testl %r10d, %r10d
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store1@PLT
+
+; CHECK: .type __asan_check_store2_rn[[RN2]],@function
+; CHECK-NEXT: .weak __asan_check_store2_rn[[RN2]]
+; CHECK-NEXT: .hidden __asan_check_store2_rn[[RN2]]
+; CHECK-NEXT: __asan_check_store2_rn[[RN2]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: movsbl 2147450880(%r10), %r10d
+; CHECK-NEXT: testl %r10d, %r10d
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $1, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store2@PLT
+
+; CHECK: .type __asan_check_store4_rn[[RN4]],@function
+; CHECK-NEXT: .weak __asan_check_store4_rn[[RN4]]
+; CHECK-NEXT: .hidden __asan_check_store4_rn[[RN4]]
+; CHECK-NEXT: __asan_check_store4_rn[[RN4]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: movsbl 2147450880(%r10), %r10d
+; CHECK-NEXT: testl %r10d, %r10d
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $3, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store4@PLT
+
+; CHECK: .type __asan_check_store8_rn[[RN8]],@function
+; CHECK-NEXT: .weak __asan_check_store8_rn[[RN8]]
+; CHECK-NEXT: .hidden __asan_check_store8_rn[[RN8]]
+; CHECK-NEXT: __asan_check_store8_rn[[RN8]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: cmpb $0, 2147450880(%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store8@PLT
+
+; CHECK: .type __asan_check_store16_rn[[RN16]],@function
+; CHECK-NEXT: .weak __asan_check_store16_rn[[RN16]]
+; CHECK-NEXT: .hidden __asan_check_store16_rn[[RN16]]
+; CHECK-NEXT: __asan_check_store16_rn[[RN16]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: cmpw $0, 2147450880(%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store16@PLT
+
declare void @llvm.asan.check.memaccess(i8*, i32 immarg)
diff --git a/llvm/test/CodeGen/X86/asan-check-memaccess-or.ll b/llvm/test/CodeGen/X86/asan-check-memaccess-or.ll
--- a/llvm/test/CodeGen/X86/asan-check-memaccess-or.ll
+++ b/llvm/test/CodeGen/X86/asan-check-memaccess-or.ll
@@ -1,11 +1,256 @@
-; XFAIL: *
-; RUN: llc < %s
+; RUN: llc < %s | FileCheck %s
target triple = "x86_64-pc-win"
define void @load1(i8* nocapture readonly %x) {
+; CHECK: pushq %rax
+; CHECK-NOT: push %rbp
+; CHECK: callq __asan_check_load1_rn[[RN1:.*]]
+; CHECK: callq __asan_check_store1_rn[[RN1]]
+; CHECK-NOT: pop %rbp
+; CHECK: popq %rax
call void @llvm.asan.check.memaccess(i8* %x, i32 0)
+ call void @llvm.asan.check.memaccess(i8* %x, i32 32)
ret void
}
+define void @load2(i16* nocapture readonly %x) {
+; CHECK: pushq %rax
+; CHECK-NOT: push %rbp
+; CHECK: callq __asan_check_load2_rn[[RN2:.*]]
+; CHECK: callq __asan_check_store2_rn[[RN2]]
+; CHECK-NOT: pop %rbp
+; CHECK: popq %rax
+ %1 = ptrtoint i16* %x to i64
+ %2 = bitcast i16* %x to i8*
+ call void @llvm.asan.check.memaccess(i8* %2, i32 2)
+ call void @llvm.asan.check.memaccess(i8* %2, i32 34)
+ ret void
+}
+
+define void @load4(i32* nocapture readonly %x) {
+; CHECK: pushq %rax
+; CHECK-NOT: push %rbp
+; CHECK: callq __asan_check_load4_rn[[RN4:.*]]
+; CHECK: callq __asan_check_store4_rn[[RN4]]
+; CHECK-NOT: pop %rbp
+; CHECK: popq %rax
+ %1 = ptrtoint i32* %x to i64
+ %2 = bitcast i32* %x to i8*
+ call void @llvm.asan.check.memaccess(i8* %2, i32 4)
+ call void @llvm.asan.check.memaccess(i8* %2, i32 36)
+ ret void
+}
+define void @load8(i64* nocapture readonly %x) {
+; CHECK: pushq %rax
+; CHECK-NOT: push %rbp
+; CHECK: callq __asan_check_load8_rn[[RN8:.*]]
+; CHECK: callq __asan_check_store8_rn[[RN8]]
+; CHECK-NOT: pop %rbp
+; CHECK: popq %rax
+ %1 = ptrtoint i64* %x to i64
+ %2 = bitcast i64* %x to i8*
+ call void @llvm.asan.check.memaccess(i8* %2, i32 6)
+ call void @llvm.asan.check.memaccess(i8* %2, i32 38)
+ ret void
+}
+
+define void @load16(i128* nocapture readonly %x) {
+; CHECK: pushq %rax
+; CHECK-NOT: push %rbp
+; CHECK: callq __asan_check_load16_rn[[RN16:.*]]
+; CHECK: callq __asan_check_store16_rn[[RN16]]
+; CHECK-NOT: pop %rbp
+; CHECK: popq %rax
+ %1 = ptrtoint i128* %x to i64
+ %2 = bitcast i128* %x to i8*
+ call void @llvm.asan.check.memaccess(i8* %2, i32 8)
+ call void @llvm.asan.check.memaccess(i8* %2, i32 40)
+ ret void
+}
+
+; CHECK: .type __asan_check_load1_rn[[RN1]],@function
+; CHECK-NEXT: .weak __asan_check_load1_rn[[RN1]]
+; CHECK-NEXT: .hidden __asan_check_load1_rn[[RN1]]
+; CHECK-NEXT: __asan_check_load1_rn[[RN1]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10{{.*}}
+; CHECK-NEXT: movb (%r10), %r10b
+; CHECK-NEXT: testb %r10b, %r10b
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load1
+
+; CHECK: .type __asan_check_load2_rn[[RN2]],@function
+; CHECK-NEXT: .weak __asan_check_load2_rn[[RN2]]
+; CHECK-NEXT: .hidden __asan_check_load2_rn[[RN2]]
+; CHECK-NEXT: __asan_check_load2_rn[[RN2]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10{{.*}}
+; CHECK-NEXT: movb (%r10), %r10b
+; CHECK-NEXT: testb %r10b, %r10b
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $1, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load2
+
+; CHECK: .type __asan_check_load4_rn[[RN4]],@function
+; CHECK-NEXT: .weak __asan_check_load4_rn[[RN4]]
+; CHECK-NEXT: .hidden __asan_check_load4_rn[[RN4]]
+; CHECK-NEXT: __asan_check_load4_rn[[RN4]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10{{.*}}
+; CHECK-NEXT: movb (%r10), %r10b
+; CHECK-NEXT: testb %r10b, %r10b
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $3, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load4
+
+; CHECK: .type __asan_check_load8_rn[[RN8]],@function
+; CHECK-NEXT: .weak __asan_check_load8_rn[[RN8]]
+; CHECK-NEXT: .hidden __asan_check_load8_rn[[RN8]]
+; CHECK-NEXT: __asan_check_load8_rn[[RN8]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10{{.*}}
+; CHECK-NEXT: cmpb $0, (%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load8
+
+; CHECK: .type __asan_check_load16_rn[[RN16]],@function
+; CHECK-NEXT: .weak __asan_check_load16_rn[[RN16]]
+; CHECK-NEXT: .hidden __asan_check_load16_rn[[RN16]]
+; CHECK-NEXT: __asan_check_load16_rn[[RN16]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10{{.*}}
+; CHECK-NEXT: cmpw $0, (%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_load16
+
+; CHECK: .type __asan_check_store1_rn[[RN1]],@function
+; CHECK-NEXT: .weak __asan_check_store1_rn[[RN1]]
+; CHECK-NEXT: .hidden __asan_check_store1_rn[[RN1]]
+; CHECK-NEXT: __asan_check_store1_rn[[RN1]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10
+; CHECK-NEXT: movb (%r10), %r10b
+; CHECK-NEXT: testb %r10b, %r10b
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store1@PLT
+
+; CHECK: .type __asan_check_store2_rn[[RN2]],@function
+; CHECK-NEXT: .weak __asan_check_store2_rn[[RN2]]
+; CHECK-NEXT: .hidden __asan_check_store2_rn[[RN2]]
+; CHECK-NEXT: __asan_check_store2_rn[[RN2]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10
+; CHECK-NEXT: movb (%r10), %r10b
+; CHECK-NEXT: testb %r10b, %r10b
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $1, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store2@PLT
+
+; CHECK: .type __asan_check_store4_rn[[RN4]],@function
+; CHECK-NEXT: .weak __asan_check_store4_rn[[RN4]]
+; CHECK-NEXT: .hidden __asan_check_store4_rn[[RN4]]
+; CHECK-NEXT: __asan_check_store4_rn[[RN4]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10
+; CHECK-NEXT: movb (%r10), %r10b
+; CHECK-NEXT: testb %r10b, %r10b
+; CHECK-NEXT: jne [[EXTRA:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[EXTRA]]:
+; CHECK-NEXT: movq [[REG]], %r11
+; CHECK-NEXT: andl $7, %r11d
+; CHECK-NEXT: addl $3, %r11d
+; CHECK-NEXT: cmpl %r10d, %r11d
+; CHECK-NEXT: jl [[RET]]
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store4@PLT
+
+; CHECK: .type __asan_check_store8_rn[[RN8]],@function
+; CHECK-NEXT: .weak __asan_check_store8_rn[[RN8]]
+; CHECK-NEXT: .hidden __asan_check_store8_rn[[RN8]]
+; CHECK-NEXT: __asan_check_store8_rn[[RN8]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10{{.*}}
+; CHECK-NEXT: cmpb $0, (%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store8@PLT
+
+; CHECK: .type __asan_check_store16_rn[[RN16]],@function
+; CHECK-NEXT: .weak __asan_check_store16_rn[[RN16]]
+; CHECK-NEXT: .hidden __asan_check_store16_rn[[RN16]]
+; CHECK-NEXT: __asan_check_store16_rn[[RN16]]:
+; CHECK-NEXT: movq [[REG:.*]], %r10
+; CHECK-NEXT: shrq $3, %r10
+; CHECK-NEXT: orq $17592186044416, %r10{{.*}}
+; CHECK-NEXT: cmpw $0, (%r10)
+; CHECK-NEXT: jne [[FAIL:.*]]
+; CHECK-NEXT: [[RET:.*]]:
+; CHECK-NEXT: retq
+; CHECK-NEXT: [[FAIL]]:
+; CHECK-NEXT: movq [[REG:.*]], %rdi
+; CHECK-NEXT: jmp __asan_report_store16@PLT
+
declare void @llvm.asan.check.memaccess(i8*, i32 immarg)