diff --git a/.Rbuildignore b/.Rbuildignore index 493e59bb..82fd49b5 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -17,3 +17,4 @@ ^tests/testthat/pkg/RcppParallelTest/src/.*\.s?o$ ^tools/tbb$ ^\.github$ +^patches \ No newline at end of file diff --git a/R/tbb.R b/R/tbb.R index d881fd8f..49b42591 100644 --- a/R/tbb.R +++ b/R/tbb.R @@ -49,8 +49,14 @@ tbbCxxFlags <- function() { flags <- character() # opt-in to TBB on Windows - if (is_windows()) + if (is_windows()) { flags <- c(flags, "-DRCPP_PARALLEL_USE_TBB=1") + if (R.version$arch == "aarch64") { + # TBB does not have assembly code for Windows ARM64 + # so we need to use compiler builtins + flags <- c(flags, "-DTBB_USE_GCC_BUILTINS") + } + } # if TBB_INC is set, apply those library paths tbbInc <- Sys.getenv("TBB_INC", unset = TBB_INC) @@ -81,10 +87,6 @@ tbbLdFlags <- function() { return(sprintf(fmt, asBuildPath(tbbLib))) } - # on Aarch64 builds, use the version of TBB provided by Rtools - if (is_windows() && R.version$arch == "aarch64") - return("-ltbb12 -ltbbmalloc") - # on Mac, Windows and Solaris, we need to explicitly link (#206) needsExplicitFlags <- is_mac() || is_windows() || (is_solaris() && !is_sparc()) if (needsExplicitFlags) { diff --git a/R/zzz.R b/R/zzz.R index 2e284705..31c40a3e 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -27,12 +27,8 @@ loadTbbLibrary <- function(name) { .onLoad <- function(libname, pkgname) { - tbbLibraryName <- "tbb" - if (is_windows() && R.version$arch == "aarch64") - tbbLibraryName <- "tbb12" - # load tbb, tbbmalloc - .tbbDllInfo <<- loadTbbLibrary(tbbLibraryName) + .tbbDllInfo <<- loadTbbLibrary("tbb") .tbbMallocDllInfo <<- loadTbbLibrary("tbbmalloc") # load tbbmalloc_proxy, but only if requested diff --git a/inst/include/RcppParallel.h b/inst/include/RcppParallel.h index 637c16d4..cbd5ef45 100644 --- a/inst/include/RcppParallel.h +++ b/inst/include/RcppParallel.h @@ -18,6 +18,9 @@ #endif #if RCPP_PARALLEL_USE_TBB +#if defined(WINNT) && defined(__aarch64__) && !defined(TBB_USE_GCC_BUILTINS) +#define TBB_USE_GCC_BUILTINS 1 +#endif # include "RcppParallel/TBB.h" #endif diff --git a/patches/windows_arm64.diff b/patches/windows_arm64.diff new file mode 100644 index 00000000..ff883e82 --- /dev/null +++ b/patches/windows_arm64.diff @@ -0,0 +1,47 @@ +diff --git a/src/tbb/build/Makefile.tbb b/src/tbb/build/Makefile.tbb +index 8d155f80..c58f4fb1 100644 +--- a/src/tbb/build/Makefile.tbb ++++ b/src/tbb/build/Makefile.tbb +@@ -91,7 +91,11 @@ ifneq (,$(TBB.DEF)) + tbb.def: $(TBB.DEF) $(TBB.LST) + $(CPLUS) $(PREPROC_ONLY) $< $(CPLUS_FLAGS) $(INCLUDES) > $@ + +-LIB_LINK_FLAGS += $(EXPORT_KEY)tbb.def ++# LLVM on Windows doesn't need --version-script export ++# https://reviews.llvm.org/D63743 ++ifeq (, $(WINARM64_CLANG)) ++ LIB_LINK_FLAGS += $(EXPORT_KEY)tbb.def ++endif + $(TBB.DLL): tbb.def + endif + +diff --git a/src/tbb/build/Makefile.tbbmalloc b/src/tbb/build/Makefile.tbbmalloc +index 421e95c5..e7c38fa4 100644 +--- a/src/tbb/build/Makefile.tbbmalloc ++++ b/src/tbb/build/Makefile.tbbmalloc +@@ -74,7 +74,11 @@ ifneq (,$(MALLOC.DEF)) + tbbmalloc.def: $(MALLOC.DEF) + $(CPLUS) $(PREPROC_ONLY) $< $(M_CPLUS_FLAGS) $(WARNING_SUPPRESS) $(INCLUDES) > $@ + +-MALLOC_LINK_FLAGS += $(EXPORT_KEY)tbbmalloc.def ++# LLVM on Windows doesn't need --version-script export ++# https://reviews.llvm.org/D63743 ++ifeq (, $(WINARM64_CLANG)) ++ MALLOC_LINK_FLAGS += $(EXPORT_KEY)tbbmalloc.def ++endif + $(MALLOC.DLL): tbbmalloc.def + endif + +diff --git a/src/tbb/src/tbbmalloc/TypeDefinitions.h b/src/tbb/src/tbbmalloc/TypeDefinitions.h +index 3178442e..fd4b7956 100644 +--- a/src/tbb/src/tbbmalloc/TypeDefinitions.h ++++ b/src/tbb/src/tbbmalloc/TypeDefinitions.h +@@ -25,7 +25,7 @@ + # define __ARCH_ipf 1 + # elif defined(_M_IX86)||defined(__i386__) // the latter for MinGW support + # define __ARCH_x86_32 1 +-# elif defined(_M_ARM) ++# elif defined(_M_ARM) || defined(__aarch64__) + # define __ARCH_other 1 + # else + # error Unknown processor architecture for Windows diff --git a/src/Makevars.in b/src/Makevars.in index af771924..7fa02e1f 100644 --- a/src/Makevars.in +++ b/src/Makevars.in @@ -21,6 +21,17 @@ ifeq ($(OS), Windows_NT) USE_TBB=Windows TBB_COPY_PATTERN=tbb*.dll + ARCH=$(shell "${R_HOME}/bin/R" --vanilla -s -e 'cat(R.version$$arch)') + TBB_CXXFLAGS = @CXX11FLAGS@ -DTBB_NO_LEGACY=1 + ifeq "$(ARCH)" "aarch64" + PKG_CPPFLAGS += -DTBB_USE_GCC_BUILTINS + TBB_CXXFLAGS += -DTBB_USE_GCC_BUILTINS + CLANG_CHECK := $(shell echo | $(CC) -E -dM - | findstr __clang__) + ifneq ($(CLANG_CHECK), ) + WINARM64_CLANG=true + endif + endif + MAKE = make MAKEFLAGS = -e -j1 MAKE_CMD = \ @@ -28,9 +39,10 @@ ifeq ($(OS), Windows_NT) CYGWIN=nodosfilewarning \ CONLY="@WINDOWS_CC@" \ CPLUS="@WINDOWS_CXX11@" \ - CXXFLAGS="@CXX11FLAGS@ -DTBB_NO_LEGACY=1" \ + CXXFLAGS="$(TBB_CXXFLAGS)" \ PIC_KEY="@CXX11PICFLAGS@" \ WARNING_SUPPRESS="" \ + WINARM64_CLANG="$(WINARM64_CLANG)" \ $(MAKE) else @@ -77,26 +89,21 @@ ifeq ($(USE_TBB), Windows) # rtools: turn on hacks to compensate for make and shell differences rtools<=>MinGW # compiler: overwrite default (which is cl = MS compiler) MAKE_ARGS += rtools=true compiler=gcc - ifeq ($(WIN), 64) - MAKE_ARGS += arch=intel64 runtime=mingw - ARCH_DIR=x64/ - else - MAKE_ARGS += arch=ia32 runtime=mingw - ARCH_DIR=i386/ + # TBB configure will detect mingw runtime with unknown arch on WINARM64_CLANG but not an + # issue as we are using compiler built-ins instead of arch-specific code + ifneq ($(WINARM64_CLANG), true) + ifeq ($(WIN), 64) + MAKE_ARGS += arch=intel64 runtime=mingw + ARCH_DIR=x64/ + else + MAKE_ARGS += arch=ia32 runtime=mingw + ARCH_DIR=i386/ + endif endif # Linker needs access to the tbb dll; otherwise you get errors such as: # "undefined reference to `tbb::task_scheduler_init::terminate()'" PKG_LIBS += -Ltbb/build/lib_release -ltbb -ltbbmalloc - - # override for aarch64 (experimental) to use Rtools TBB - ARCH=$(shell "${R_HOME}/bin/R" --vanilla -s -e 'cat(R.version$$arch)') - ifeq "$(ARCH)" "aarch64" - TBB_LIB = ${R_TOOLS_SOFT} - TBB_INC = ${R_TOOLS_SOFT} - PKG_LIBS = -ltbb12 -ltbbmalloc - endif - endif # write compiler if set diff --git a/src/tbb/build/Makefile.tbb b/src/tbb/build/Makefile.tbb index 8d155f80..c58f4fb1 100644 --- a/src/tbb/build/Makefile.tbb +++ b/src/tbb/build/Makefile.tbb @@ -91,7 +91,11 @@ ifneq (,$(TBB.DEF)) tbb.def: $(TBB.DEF) $(TBB.LST) $(CPLUS) $(PREPROC_ONLY) $< $(CPLUS_FLAGS) $(INCLUDES) > $@ -LIB_LINK_FLAGS += $(EXPORT_KEY)tbb.def +# LLVM on Windows doesn't need --version-script export +# https://reviews.llvm.org/D63743 +ifeq (, $(WINARM64_CLANG)) + LIB_LINK_FLAGS += $(EXPORT_KEY)tbb.def +endif $(TBB.DLL): tbb.def endif diff --git a/src/tbb/build/Makefile.tbbmalloc b/src/tbb/build/Makefile.tbbmalloc index 421e95c5..e7c38fa4 100644 --- a/src/tbb/build/Makefile.tbbmalloc +++ b/src/tbb/build/Makefile.tbbmalloc @@ -74,7 +74,11 @@ ifneq (,$(MALLOC.DEF)) tbbmalloc.def: $(MALLOC.DEF) $(CPLUS) $(PREPROC_ONLY) $< $(M_CPLUS_FLAGS) $(WARNING_SUPPRESS) $(INCLUDES) > $@ -MALLOC_LINK_FLAGS += $(EXPORT_KEY)tbbmalloc.def +# LLVM on Windows doesn't need --version-script export +# https://reviews.llvm.org/D63743 +ifeq (, $(WINARM64_CLANG)) + MALLOC_LINK_FLAGS += $(EXPORT_KEY)tbbmalloc.def +endif $(MALLOC.DLL): tbbmalloc.def endif diff --git a/src/tbb/src/tbbmalloc/TypeDefinitions.h b/src/tbb/src/tbbmalloc/TypeDefinitions.h index 3178442e..fd4b7956 100644 --- a/src/tbb/src/tbbmalloc/TypeDefinitions.h +++ b/src/tbb/src/tbbmalloc/TypeDefinitions.h @@ -25,7 +25,7 @@ # define __ARCH_ipf 1 # elif defined(_M_IX86)||defined(__i386__) // the latter for MinGW support # define __ARCH_x86_32 1 -# elif defined(_M_ARM) +# elif defined(_M_ARM) || defined(__aarch64__) # define __ARCH_other 1 # else # error Unknown processor architecture for Windows