diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -626,6 +626,11 @@ return Info->get(Inst.getOpcode()).mayStore(); } + virtual bool isAArch64Exclusive(const MCInst &Inst) const { + llvm_unreachable("not implemented"); + return false; + } + virtual bool isCleanRegXOR(const MCInst &Inst) const { llvm_unreachable("not implemented"); return false; diff --git a/bolt/lib/Passes/Instrumentation.cpp b/bolt/lib/Passes/Instrumentation.cpp --- a/bolt/lib/Passes/Instrumentation.cpp +++ b/bolt/lib/Passes/Instrumentation.cpp @@ -13,6 +13,7 @@ #include "bolt/Passes/Instrumentation.h" #include "bolt/Core/ParallelUtilities.h" #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h" +#include "bolt/Utils/CommandLineOpts.h" #include "bolt/Utils/Utils.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/RWMutex.h" @@ -85,6 +86,24 @@ namespace llvm { namespace bolt { +static bool hasAArch64ExclusiveMemop(BinaryFunction &Function) { + // FIXME ARMv8-a architecture reference manual says that software must avoid + // having any explicit memory accesses between exclusive load and associated + // store instruction. So for now skip instrumentation for functions that have + // these instructions, since it might lead to runtime deadlock. + BinaryContext &BC = Function.getBinaryContext(); + for (const BinaryBasicBlock &BB : Function) + for (const MCInst &Inst : BB) + if (BC.MIB->isAArch64Exclusive(Inst)) { + if (opts::Verbosity >= 1) + outs() << "BOLT-INSTRUMENTER: Function " << Function + << " has exclusive instructions, skip instrumentation\n"; + return true; + } + + return false; +} + uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction &Function) { auto Iter = FuncToStringIdx.find(&Function); if (Iter != FuncToStringIdx.end()) @@ -288,6 +307,9 @@ if (BC.isMachO() && Function.hasName("___GLOBAL_init_65535/1")) return; + if (BC.isAArch64() && hasAArch64ExclusiveMemop(Function)) + return; + SplitWorklistTy SplitWorklist; SplitInstrsTy SplitInstrs; diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp --- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp @@ -272,6 +272,34 @@ return isLDRB(Inst) || isLDRH(Inst) || isLDRW(Inst) || isLDRX(Inst); } + bool isAArch64Exclusive(const MCInst &Inst) const override { + return (Inst.getOpcode() == AArch64::LDXPX || + Inst.getOpcode() == AArch64::LDXPW || + Inst.getOpcode() == AArch64::LDXRX || + Inst.getOpcode() == AArch64::LDXRW || + Inst.getOpcode() == AArch64::LDXRH || + Inst.getOpcode() == AArch64::LDXRB || + Inst.getOpcode() == AArch64::STXPX || + Inst.getOpcode() == AArch64::STXPW || + Inst.getOpcode() == AArch64::STXRX || + Inst.getOpcode() == AArch64::STXRW || + Inst.getOpcode() == AArch64::STXRH || + Inst.getOpcode() == AArch64::STXRB || + Inst.getOpcode() == AArch64::LDAXPX || + Inst.getOpcode() == AArch64::LDAXPW || + Inst.getOpcode() == AArch64::LDAXRX || + Inst.getOpcode() == AArch64::LDAXRW || + Inst.getOpcode() == AArch64::LDAXRH || + Inst.getOpcode() == AArch64::LDAXRB || + Inst.getOpcode() == AArch64::STLXPX || + Inst.getOpcode() == AArch64::STLXPW || + Inst.getOpcode() == AArch64::STLXRX || + Inst.getOpcode() == AArch64::STLXRW || + Inst.getOpcode() == AArch64::STLXRH || + Inst.getOpcode() == AArch64::STLXRB || + Inst.getOpcode() == AArch64::CLREX); + } + bool isLoadFromStack(const MCInst &Inst) const { if (!mayLoad(Inst)) return false; diff --git a/bolt/test/AArch64/exclusive-instrument.s b/bolt/test/AArch64/exclusive-instrument.s new file mode 100644 --- /dev/null +++ b/bolt/test/AArch64/exclusive-instrument.s @@ -0,0 +1,39 @@ +// This test checks that the foo function having exclusive memory access +// instructions won't be instrumented. + +// REQUIRES: system-linux,bolt-runtime,target=aarch64{{.*}} + +// RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown \ +// RUN: %s -o %t.o +// RUN: %clang %cflags -fPIC -pie %t.o -o %t.exe -nostdlib -Wl,-q -Wl,-fini=dummy +// RUN: llvm-bolt %t.exe -o %t.bolt -instrument -v=1 | FileCheck %s + +// CHECK: Function foo has exclusive instructions, skip instrumentation + +.global foo +.type foo, %function +foo: + ldaxr w9, [x10] + cbnz w9, .Lret + stlxr w12, w11, [x9] + cbz w12, foo + clrex +.Lret: + ret +.size foo, .-foo + +.global _start +.type _start, %function +_start: + cmp x0, #0 + b.eq .Lexit + bl foo +.Lexit: + ret +.size _start, .-_start + +.global dummy +.type dummy, %function +dummy: + ret +.size dummy, .-dummy