diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java index 21ba0f7cf65585a0710a2e12aea44fb96313828f..40b50efaff08bbc0779f95954056d37a65e38ade 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/llvm/TruffleLLVM_DLL.java @@ -23,13 +23,20 @@ package com.oracle.truffle.r.ffi.impl.llvm; import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import javax.naming.NameAlreadyBoundException; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.r.runtime.RInternalError; @@ -128,8 +135,23 @@ public class TruffleLLVM_DLL implements DLLRFFI { int totalRead = 0; while (totalRead < size && (n = zis.read(bc, totalRead, size - totalRead)) != -1) { totalRead += n; - LLVM_IR ir = new LLVM_IR.Binary(entry.getName(), bc); - irList.add(ir); + } + Path zipName = Paths.get(entry.getName()); + String name = zipName.getFileName().toString(); + int ix = name.indexOf('.'); + if (ix > 0) { + name = name.substring(0, ix); + } + LLVM_IR.Binary ir = new LLVM_IR.Binary(name, bc); + irList.add(ir); + // debugging + if (System.getenv("FASTR_LLVM_DEBUG") != null) { + try (FileOutputStream bs = new FileOutputStream(Paths.get("tmpzip", name).toString())) { + bs.write(bc); + } + try (PrintStream bs = new PrintStream(new FileOutputStream(Paths.get("tmpb64", name).toString()))) { + bs.print(ir.base64); + } } } LLVM_IR[] result = new LLVM_IR[irList.size()]; diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/README.md b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/README.md index 8ed7f6488940a668caaa87bc059f8e7c9f9fc579..3b2ad0add58a0ce18ea51ddb396b571ac707875e 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/README.md +++ b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/README.md @@ -1,2 +1,2 @@ The C code in this directory is never compiled by the standard C compiler to create compiled object code. -It is compiled solely to create LLVM IR which is interpreted at runtime. This is controlled by the -DFASTR_LLVM "compiler" flag. +It is compiled solely to create LLVM IR which is interpreted at runtime. \ No newline at end of file diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.c b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.c deleted file mode 100644 index 4ad1b6b8d8df5d22e2431a5652d1a4fbfe42b8f8..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -// A dummy file that is compiled (by fastr-cc) in place of any actual .c file in this directory. -// This allows the IR for the actual .c file to be merged with the empty .o for llvm_dummy. diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.f b/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.f deleted file mode 100644 index 6c4e6cee29e0ca31cc15e3c1429d33061508786a..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.f +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -// A dummy file that is compiled (by fastr-fc) in place of any actual .f file in this directory. -// This allows the IR for the actual .f file to be merged with the empty .o for llvm_dummy. diff --git a/com.oracle.truffle.r.native/gnur/edLLVM b/com.oracle.truffle.r.native/gnur/edLLVM index 8b3e2a29d29f02e0db41b5778140ced45d5b8171..4cefc6d92562aeb914d69b7c2aff95ad6800a5a6 100644 --- a/com.oracle.truffle.r.native/gnur/edLLVM +++ b/com.oracle.truffle.r.native/gnur/edLLVM @@ -1,12 +1,12 @@ /^CC =/ d i -CC = $(FASTR_R_HOME)/mx.fastr/compilers/fastr-cc +CC = $(FASTR_NATIVE_DIR)/llvm_tools/llvm-cc . /^F77 =/ d i -F77 = $(FASTR_R_HOME)/mx.fastr/compilers/fastr-fc +F77 = $(FASTR_NATIVE_DIR)/llvm_tools/llvm-fc . w q diff --git a/mx.fastr/compilers/fastr-cc b/com.oracle.truffle.r.native/llvm_tools/llvm-c++ similarity index 66% rename from mx.fastr/compilers/fastr-cc rename to com.oracle.truffle.r.native/llvm_tools/llvm-c++ index 30f313e3a287814402448df82b89f8b5978464f4..6708749372cf282269fb11f1cd6c9bae4e67a492 100755 --- a/mx.fastr/compilers/fastr-cc +++ b/com.oracle.truffle.r.native/llvm_tools/llvm-c++ @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,25 +23,20 @@ #!/bin/bash SOURCE="$0" -while [ -h "$SOURCE" ]; do - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" -done DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" -with_sulong=0 -while [ $DIR != "/" ] ; do - if [ -d $DIR/sulong ] && [ -d $DIR/sulong/mx.sulong ] ; then - with_sulong=1 - break - fi - DIR=`dirname $DIR` -done +. $DIR/llvm-helper +fortran=0 +analyze_args "$@" -if [ $with_sulong = 1 ] && [ "$FASTR_SULONG_IGNORE" = "" ] ; then - MX_PRIMARY_SUITE_PATH=$DIR/fastr mx --dynamicimport sulong fastr-cc $@ +if [ $is_link -eq 1 ] +then + create_bc_lib "$@" else - gcc $@ + llvm_tool=clang++ + get_llvm_tool + runit $llvm_tool_bin $llvm_args + mem2reg_opt + fake_obj fi diff --git a/mx.fastr/compilers/fastr-cpp b/com.oracle.truffle.r.native/llvm_tools/llvm-cc similarity index 66% rename from mx.fastr/compilers/fastr-cpp rename to com.oracle.truffle.r.native/llvm_tools/llvm-cc index 26444e34c001fa91a9208e99298ebc830aaff4c0..69ddd766c92d216024bd3c330e07dc91c482ac28 100755 --- a/mx.fastr/compilers/fastr-cpp +++ b/com.oracle.truffle.r.native/llvm_tools/llvm-cc @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,24 +23,22 @@ #!/bin/bash SOURCE="$0" -while [ -h "$SOURCE" ]; do - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" -done DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" -with_sulong=0 -while [ $DIR != "/" ] ; do - if [ -d $DIR/sulong ] && [ -d $DIR/sulong/mx.sulong ] ; then - with_sulong=1 - break - fi - DIR=`dirname $DIR` -done +. $DIR/llvm-helper +fortran=0 +analyze_args "$@" -if [ $with_sulong = 1 ] && [ "$FASTR_SULONG_IGNORE" = "" ] ; then - MX_PRIMARY_SUITE_PATH=$DIR/fastr mx --dynamicimport sulong fastr-cpp $@ + +if [ $is_link -eq 1 ] +then + create_bc_lib "$@" else - cpp $@ + llvm_tool=clang + get_llvm_tool + runit $llvm_tool_bin $llvm_args + mem2reg_opt + fake_obj fi + + diff --git a/mx.fastr/compilers/fastr-fc b/com.oracle.truffle.r.native/llvm_tools/llvm-fc similarity index 57% rename from mx.fastr/compilers/fastr-fc rename to com.oracle.truffle.r.native/llvm_tools/llvm-fc index 741eacb49c1f0f2a130e39c9702646898f842fdf..1cbd62881872c119b531b496155f13db4f34aab1 100755 --- a/mx.fastr/compilers/fastr-fc +++ b/com.oracle.truffle.r.native/llvm_tools/llvm-fc @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,25 +23,42 @@ #!/bin/bash SOURCE="$0" -while [ -h "$SOURCE" ]; do - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" -done DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" -with_sulong=0 -while [ $DIR != "/" ] ; do - if [ -d $DIR/sulong ] && [ -d $DIR/sulong/mx.sulong ] ; then - with_sulong=1 - break - fi - DIR=`dirname $DIR` -done - -if [ $with_sulong = 1 ] && [ "$FASTR_SULONG_IGNORE" = "" ] ; then - MX_PRIMARY_SUITE_PATH=$DIR/fastr mx --dynamicimport sulong fastr-fc $@ -else - gfortran $@ +. $DIR/llvm-helper +fortran=1 +analyze_args "$@" + +if [ -z "$FASTR_LLVM_GFORTRAN" ] +then + echo FASTR_LLVM_GFORTRAN must be set + exit 1 +fi + +if [ -z "$FASTR_LLVM_GFORTRAN_LLVM_AS" ] +then + echo FASTR_LLVM_GFORTRAN_LLVM_AS must be set + exit 1 +fi + +if [ -z "$FASTR_LLVM_DRAGONEGG" ] +then + echo FASTR_DRAGONEGG must be set + exit 1 fi +function ll_to_bc() { + f=`basename $llvm_ir_file` + d=`dirname $llvm_ir_file` + llvm_ir_bc_file=${d}/${f%%.*}.bc +} + + +runit $FASTR_LLVM_GFORTRAN -fplugin=$FASTR_LLVM_DRAGONEGG -fplugin-arg-dragonegg-emit-ir $llvm_args +ll_to_bc +runit $FASTR_LLVM_GFORTRAN_LLVM_AS $llvm_ir_file -o $llvm_ir_bc_file +runit rm $llvm_ir_file +llvm_ir_file=$llvm_ir_bc_file +mem2reg_opt +fake_obj + diff --git a/com.oracle.truffle.r.native/llvm_tools/llvm-helper b/com.oracle.truffle.r.native/llvm_tools/llvm-helper new file mode 100644 index 0000000000000000000000000000000000000000..058eb34e7c9099dd368bd056028b4a52625292b4 --- /dev/null +++ b/com.oracle.truffle.r.native/llvm_tools/llvm-helper @@ -0,0 +1,160 @@ +# +# Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# Helper functions for llvm-cc et al +# Global variables are set by these functions + +if [ -n "$FASTR_LLVM_TOOLMODE" ] +then + run_mode=$FASTR_LLVM_TOOLMODE +else + run_mode="run" +fi + +function runit() { + if [ $run_mode == "echo" ] + then + echo $@ + elif [ $run_mode == "echorun" ] + then + echo $@ + $@ + else + $@ + fi +} + +# Input: all the arguments to the original command line +# Global variables set: +# llvm_ir_file: name of file containing LLVM IR, e.g. foo.bc +# llvm_file_ext: extension of above, e.g. .bc +# llvm_args: processed arguments to pass to llvm tool, e.g. clang + +function analyze_args() { + llvm_args="-g " + if [ $fortran -eq 1 ] + then + llvm_args+='-S ' + llvm_file_ext='.ll' + else + llvm_file_ext='.bc' + llvm_args+='-emit-llvm ' + fi + + is_link=0 + llvm_ir_file="" + + while [[ $# -gt 0 ]] + do + llvm_args+="$1 " + case $1 in + -o) + shift + p=$1 + f=`basename $p` + d=`dirname $p` + ext=${f##*.} + if [ $ext == 'so' ] || [ $ext == 'dylib' ] + then + is_link=1 + elif [ $ext == 'o' ] + then + llvm_ir_file=${d}/${f%%.*} + llvm_ir_file+=$llvm_file_ext + llvm_args+="$llvm_ir_file " + fi + ;; + *) + ;; + esac + shift + done +} + +# Input arguments: +# llvm_tool: name of tool to find +# Global variables set: +# path to tool (defaults to plain ${llvm_tool}, assumed to be on the PATH) + +function get_llvm_tool() { + if [ -n "${FASTR_LLVM_HOME}" ] + then + llvm_tool_bin=${FASTR_LLVM_HOME}/${llvm_tool} + else + llvm_tool_uc=`echo ${llvm_tool} | tr /a-z/ /A-Z/ | tr /+/ /P/` + x=FASTR_LLVM_${llvm_tool_uc} + if [ -n "${!x}" ] + then + llvm_tool_bin=${!x} + else + llvm_tool_bin=${llvm_tool} + fi + fi +} + + +function mem2reg_opt() { + llvm_tool="opt" + get_llvm_tool + runit ${llvm_tool_bin} -mem2reg $llvm_ir_file -o ${llvm_ir_file}.opt + rc=$? + if [ $rc -eq 0 ] + then + runit mv ${llvm_ir_file}.opt $llvm_ir_file + fi +} + +function fake_obj() { + f=`basename $llvm_ir_file` + d=`dirname $llvm_ir_file` + runit touch ${d}/${f%%.*}.o +} + +# Input: all the arguments to the original command line +function create_bc_lib() { + bcfiles="" + lib="" + while [[ $# -gt 0 ]] + do + case $1 in + -o) + shift + lib=$1 + ;; + *) + f=$1 + ext=${f##*.} + if [ $ext == 'o' ] + then + fn=${f%%.*}.bc + bcfiles+="$fn " + fi + ;; + esac + shift + done + +# we do not have the luxury of controlling the name of the entry (unlike in python) +# it will be the pathname, which we will reduce to a module name on input in FastR + + runit zip -r $lib $bcfiles +} diff --git a/com.oracle.truffle.r.native/run/Makefile b/com.oracle.truffle.r.native/run/Makefile index b874c77c3859c4d0bbc03eba4685a0dab85a5611..b793c3585c141f73090286849a5a7e95ff62e392 100644 --- a/com.oracle.truffle.r.native/run/Makefile +++ b/com.oracle.truffle.r.native/run/Makefile @@ -53,6 +53,8 @@ ETC_FILES := $(addprefix $(GNUR_HOME)/etc/,javaconf ldpaths Renviron repositorie SHARE_FILES := $(addprefix $(GNUR_HOME)/share/,R Rd make java encodings) +LLVM_TOOLS := $(wildcard $(FASTR_NATIVE_DIR)/llvm_tools/*) + all: rundirs rcmds includedir rundirs: @@ -87,6 +89,7 @@ $(FASTR_BIN_DIR)/R: Makefile R.sh Rscript.sh Rscript_exec.sh Rclasspath.sh ed Makeconf.etc < edMakeconf.etc ifeq ($(FASTR_RFFI),llvm) ed Makeconf.etc < edMakeconf.etc.llvm + cp $(LLVM_TOOLS) $(FASTR_BIN_DIR) endif cp Makeconf.etc $(FASTR_ETC_DIR)/Makeconf cp -r $(SHARE_FILES) $(FASTR_SHARE_DIR) diff --git a/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm b/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm index cb70e3626b6ab6b841f4188717417495397362d1..b079665f85e0bd0e746a91f0ef81c9438293d91d 100644 --- a/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm +++ b/com.oracle.truffle.r.native/run/edMakeconf.etc.llvm @@ -1,32 +1,27 @@ /^CC =/ d i -CC = $(R_HOME)/mx.fastr/compilers/fastr-cc +CC = $(R_HOME)/bin/llvm-cc . /^CXX =/ d i -CXX = $(R_HOME)/mx.fastr/compilers/fastr-c++ -. -/^CXXCPP =/ -d -i -CXXCPP = $(R_HOME)/mx.fastr/compilers/fastr-cpp +CXX = $(R_HOME)/bin/llvm-c++ . /^FC =/ d i -FC = $(R_HOME)/mx.fastr/compilers/fastr-fc +FC = $(R_HOME)/bin/llvm-fc . /^F77 =/ d i -F77 = $(R_HOME)/mx.fastr/compilers/fastr-fc +F77 = $(R_HOME)/bin/llvm-fc . /^OBJC =/ d i -OBJC = $(R_HOME)/mx.fastr/compilers/fastr-cc +OBJC = $(R_HOME)/bin/llvm-cc . w q diff --git a/documentation/dev/truffle_llvm_ffi.md b/documentation/dev/truffle_llvm_ffi.md index 61dead5a44b885abf20694eaea4ddc7f2f858737..c0cbb908c0ec77477037ff3386533ea9fb05fa80 100644 --- a/documentation/dev/truffle_llvm_ffi.md +++ b/documentation/dev/truffle_llvm_ffi.md @@ -28,9 +28,9 @@ The `sulong` repository must be cloned to a sibling directory of `fastr` and bui cd sulong mx su-pulldragonegg -The `mx su-pulldragonegg` step is required to be able to compile Fortran code to LLVM, which is required by FastR.. As well as downloading DragonEgg this will also download and clang 3.2, which is needed to build DragonEgg. On Linux, it is necessary to use clang 3.2 in preference to any installed clang, e.g., 3.8, as some of the LLVM code generated by DragonEgg is syntax-incompatible with 3.8. The downloaded version is saved in `cache/tools/llvm/bin`. +The `mx su-pulldragonegg` step is required to be able to compile Fortran code to LLVM, which is required by FastR.. As well as downloading DragonEgg this will also download and clang 3.2, which is needed to build DragonEgg. On Linux, it is necessary to use clang 3.2 in preference to any installed clang, e.g., 3.8, as some of the LLVM code generated by DragonEgg is syntax-incompatible with 3.8. The downloaded version is saved in `cache/tools/llvm/bin`. Since DragonEgg only needs to be built once per platform, the shared library can be copied from the sulong tree (search for `draghonegg.so`) into a shared location foir use with FastR. -Once `dragonegg` is built, unset the `SULONG_GCC` and `SULONG_GPP` environment variables. +Once `dragonegg` is built, unset the `SULONG_GCC`, `SULONG_GFORTRAN` and `SULONG_GPP` environment variables. Sulong must be built with a more recent version of `clang` than 3.2, which means that `sulong` and `fastr` cannot be built in one step. First make sure that you have a supported version of `clang` and related tools installed, e.g., 3.8 and that they are on your `PATH`. Also if you are on MacOS and are using MacPorts, you must make symbolic links to the explicitly versioned tool names, i.e. `clang` -> `clang-mp-3.8`. This also applies to the `opt` and `llvm-link` tools. You can set these links directly in `/opt/local/bin` using `sudo` or create a local `bin` directory and place the links there, making sure that this directory is on your `PATH`. @@ -57,23 +57,35 @@ On Mac OS (with MacPorts) set: export PKG_LDFLAGS_OVERRIDE="-L/opt/local/lib -L/opt/local/lib/libgcc" -Now, ensure that `clang-3.2` is first on your `PATH` by adding the absolute path of `sulong/cache/tools/llvm/bin`. +FastR necessarily provides very fine control over the versions of the llvm tools that are used, through environment variables all beginning with `FASTR_LLVM`. It also allows FastR to be completely independent from sulong. The following variables are mandatory: -Then run `mx build`. +`FASTR_LLVM_DRAGONEGG`: the location of the DragonEgg plugin (shared library built above) +`FASTR_LLVM_GFORTRAN`: a 4.6 version of `gfortran` (see `SULONG_GFORTRAN` above) +`FASTR_LLVM_GFORTRAN_LLVM_AS`: a 3.2 version of the `llvm-as` tool. N.B. this is created in sulong as part of the `DragonEgg` build. This can also be copied to a shared location. + +The tools needed to build FastR and to install packages containing native code are `clang`, `clang++` and `opt`. Precisely which versions of these tools are used can be controlled in two ways. + +1. Set `FASTR_LLVM_HOME` to a directory containing the tools, named as above. N.B. Since MacPorts uses names of the form `clang-mp-3.8` this requires using symbolic links. E.g. create a directory called, say, `llvm-3.8` and symlink to the MacPorts binary, e.g., `clang-mp-3.8` and name it as `clang`. Then set `FASTR_LLVM_HOME` to that directory. +2. Set `FASTR_LLVM_CLANG`, `FASTR_LLVM_CLANGPP` and `FASTR_LLVM_OPT` to the actual binary images, e.g., `export FASTR_LLVM_CLANG=/opt/local/bin/clang-mp-3.8`. + +Not all versions of the llvm tools can compile FastR. `clang-3.2` that is downloaded as part of the DragonEgg build is known to work. This currently is placed in `sulong/cache/tools/llvm/bin` by the DragonEgg build and, again, can be copied to a shared location. `clang-3.8` and `clang-4.0` are known not to work, but `clang-3.9` does. + +Once the above is set up, run `mx build`. ## Running -There is no compile-time dependency between FastR and Sulong; all communication is via the Truffle Interop API. Therefore Sulong must be dynamically imported using either `mx --dynamicimport sulong` or by setting the environment variable `DEFAULT_DYNAMIC_IMPORTS=sulong`, with latter being most convenient. With this in effect, a normal `mx R` will make SuLong available. +There is no compile-time dependency between FastR and Sulong; all communication is via the Truffle Interop API. Therefore Sulong must be dynamically imported using either `mx --dynamicimport sulong` or by setting the environment variable `DEFAULT_DYNAMIC_IMPORTS=sulong`, with latter being most convenient. With this in effect, a normal `mx R` will make Sulong available. -Note that if the `LLVM_PARSE_TIME` environment variable is set to any value, the time taken to parse each LLVM module is logged to the console, which is also an indication that the LLVM implementation variant is being used. +Note that if the `LLVM_PARSE_TIME` environment variable is set to any value, the time taken to parse each LLVM module is logged to the console, which is also a check that the LLVM implementation variant is being used. # Implementation Details ## Compiler Wrapper Scripts -The compiler wrapper scripts are simple shell scripts that first test for the existence of the `sulong` sibling directory and, if it exists and the environment variable `FASTR_SULONG_IGNORE` is not set, invoke associated `mx` commands to perform the compilation. Otherwise, the standard compiler is used. The scripts are stored in the `compilers` sub-directory of `mx.fastr` and are named: `fastr-cc`, `fastr-fc`, `fastr-c++` and `fastr-cpp`. The associated `mx` commands are in `mx.fastr/mx_fastr_compilers.py`. +Compiler wrapper scripts are used to map the commands generated the `make` into an appropriate set of llvm tool invocations. This way no change is required to the `Makefile`s or the R package installation process. +Once Fastr is built, the scripts are stored in the `bin` sub-directory and are named: `llvm-cc`, `llvm-fc` and `llvm-c++`, for use during package installation. -Currently, for convenience, the Python wrappers invoke code in the Sulong `sulong/mx.sulong` directory. Eventually, they will modified to be independent of Sulong. +The scripts normally operate silently. However, if `FASTR_LLVM_TOOLMODE`is set to `echorun`, the actual llvm tool commands resulting from the normal C/C++/Fortran command will be echoed to the standard output. ## Limitations At the time of writing all the `RFFI` interfaces are implemented for LLVM. However, owing to a bug in DragonEgg, the actual Fortran code for the Lapack library is not executed under LLVM, only the wrapper. diff --git a/mx.fastr/compilers/fastr-c++ b/mx.fastr/compilers/fastr-c++ deleted file mode 100755 index 940ad0e0fecc1dc732cdb565d4a3d7301a322560..0000000000000000000000000000000000000000 --- a/mx.fastr/compilers/fastr-c++ +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -#!/bin/bash - -SOURCE="$0" -while [ -h "$SOURCE" ]; do - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" -done -DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - -with_sulong=0 -while [ $DIR != "/" ] ; do - if [ -d $DIR/sulong ] && [ -d $DIR/sulong/mx.sulong ] ; then - with_sulong=1 - break - fi - DIR=`dirname $DIR` -done - -if [ $with_sulong = 1 ] && [ "$FASTR_SULONG_IGNORE" = "" ] ; then - MX_PRIMARY_SUITE_PATH=$DIR/fastr mx --dynamicimport sulong fastr-c++ $@ -else - g++ $@ -fi - diff --git a/mx.fastr/compilers/have_sulong b/mx.fastr/compilers/have_sulong deleted file mode 100755 index 96ff8288a723c950cfc829865a399715f6b5b207..0000000000000000000000000000000000000000 --- a/mx.fastr/compilers/have_sulong +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -#!/bin/bash - -SOURCE="$0" -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located -done -DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - -with_sulong=0 -while [ $DIR != "/" ] ; do - if [ -d $DIR/sulong ] && [ -d $DIR/sulong/mx.sulong ] ; then - with_sulong=1 - break - fi - DIR=`dirname $DIR` -done - -if [ $with_sulong = 1 ] && [ "$FASTR_SULONG_IGNORE" = "" ] ; then - echo "yes" -else - echo "no" -fi diff --git a/mx.fastr/mx_fastr.py b/mx.fastr/mx_fastr.py index 6f42889ae2c4c460f992ec8a1f4cc08069038f37..5431374372b487878fbd30302ad27e0458578e4a 100644 --- a/mx.fastr/mx_fastr.py +++ b/mx.fastr/mx_fastr.py @@ -26,7 +26,6 @@ from argparse import ArgumentParser import mx import mx_gate import mx_fastr_pkgs -import mx_fastr_compile import mx_fastr_dists from mx_fastr_dists import FastRReleaseProject, FastRNativeRecommendedProject #pylint: disable=unused-import import mx_copylib @@ -511,5 +510,4 @@ _commands = { 'nativebuild' : [nativebuild, '[]'], } -_commands.update(mx_fastr_compile._commands) mx.update_commands(_fastr_suite, _commands) diff --git a/mx.fastr/mx_fastr_compile.py b/mx.fastr/mx_fastr_compile.py deleted file mode 100644 index e7b0cb1032762b05c9653b3c5c2dbefa0042b623..0000000000000000000000000000000000000000 --- a/mx.fastr/mx_fastr_compile.py +++ /dev/null @@ -1,254 +0,0 @@ -# -# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -""" -A wrapper for the C/C++/Fortran compilers that optionally handles the generation of LLVM bitcode. -When not running with sulong is simply forwards to the default compiler for the platform. -When running under sulong, it uses sulong to do two compilations; first to generate object code -and second to generate LLVM bitcode. -""" -import os, sys, zipfile -import mx -import mx_fastr - -def _sulong(): - sulong = mx.suite('sulong', fatalIfMissing=False) - if sulong: - return sulong.extensions - else: - return None - -def _is_linux(): - return sys.platform.startswith('linux') - -def _is_darwin(): - return sys.platform.startswith('darwin') - -def _log(cmd, args): - if os.environ.has_key('FASTR_COMPILE_LOGFILE'): - with open(os.environ['FASTR_COMPILE_LOGFILE'], 'a') as f: - f.write(cmd) - f.write('(') - f.write(os.getcwd()) - f.write(')') - f.write(' ') - f.write(' '.join(args)) - f.write('\n') - -class AnalyzedArgs: - ''' - is_link: True iff the command is a shared library link - llvm_ir_file: the target file for the ir derived from the .o file (only set if is_link=False) - compile_args: possibly modified args for C compilation - emit_llvm_args: the args to generate the llvm ir - ''' - def __init__(self, llvm_ir_file, is_link, compile_args, emit_llvm_args): - self.llvm_ir_file = llvm_ir_file - self.is_link = is_link - self.compile_args = compile_args - self.emit_llvm_args = emit_llvm_args - - -def _c_dummy_file(): - return os.path.join(mx_fastr._fastr_suite.dir, 'com.oracle.truffle.r.native', 'fficall', 'src', 'truffle_llvm', 'llvm_dummy.c') - -def _analyze_args(args, dragonEgg=False): - ''' - Analyzes the original arguments to the compiler and returns an adjusted - list that will run the compiler (via sulong) to extract the llvm ir. - Result is an instance of AnalyzedArgs: - ''' - compile_args = [] - emit_llvm_args = ['-g'] - llvm_ir_file_ext = '.bc' - if not dragonEgg: - emit_llvm_args.append('-emit-llvm') - else: - # dragonEgg plugin doesn't seem able to make bitcode directly - emit_llvm_args.append('-S') - llvm_ir_file_ext = '.ll' - - is_link = False - llvm_ir_file = None - c_dummy = False - i = 0 - while i < len(args): - arg = args[i] - if arg == '-DFASTR_LLVM': - c_dummy = True - i = i + 1 - continue - - emit_llvm_args.append(arg) - compile_args.append(arg) - if arg == '-c': - cfile = args[i + 1] - if c_dummy: - cfile = _c_dummy_file() - compile_args.append(cfile) - emit_llvm_args.append(args[i + 1]) - i = i + 1 - - if arg == '-o': - ext = os.path.splitext(args[i + 1])[1] - is_link = ext == '.so' or ext == '.dylib' - compile_args.append(args[i + 1]) - if ext == '.o': - llvm_ir_file = os.path.splitext(args[i + 1])[0] + llvm_ir_file_ext - emit_llvm_args.append(llvm_ir_file) - i = i + 1 - - i = i + 1 - _log('adjusted-compile-args', compile_args) - _log('emit-llvm-args', emit_llvm_args) - return AnalyzedArgs(llvm_ir_file, is_link, compile_args, emit_llvm_args) - -def compileWithClang(args=None, version=None, out=None, err=None): - return mx.run([_sulong().findLLVMProgram('clang', version)] + args, out=out, err=err) - -def compileWithClangPP(args=None, version=None, out=None, err=None): - return mx.run([_sulong().findLLVMProgram('clang++', version)] + args, out=out, err=err) - -def opt(args=None, version=None, out=None, err=None): - return mx.run([_sulong().findLLVMProgram('opt', version)] + args, out=out, err=err) - -def cc(args): - _log('fastr:cc', args) - compiler = None - sulong = _sulong() - if sulong: - analyzed_args = _analyze_args(args) - rc = 0 - if analyzed_args.is_link: - rc = _create_bc_lib(args) - else: - if analyzed_args.llvm_ir_file: - rc = compileWithClang(analyzed_args.emit_llvm_args) - if rc == 0 and not analyzed_args.is_link and analyzed_args.llvm_ir_file: - rc = _mem2reg_opt(analyzed_args.llvm_ir_file) - _fake_obj(analyzed_args.llvm_ir_file.replace('.bc', '.o')) - else: - compiler = 'clang' - rc = mx.run([compiler] + args, nonZeroIsFatal=False) - - return rc - -def fc(args): - _log('fastr:fc', args) - compiler = None - sulong = _sulong() - if sulong: - analyzed_args = _analyze_args(args, dragonEgg=True) - rc = 0 - rc = sulong.dragonEggGFortran(analyzed_args.emit_llvm_args) - if rc == 0 and analyzed_args.llvm_ir_file: - # create bitcode from textual IR - llvm_as = sulong.findLLVMProgram('llvm-as') - llvm_bc_file = os.path.splitext(analyzed_args.llvm_ir_file)[0] + '.bc' - rc = mx.run([llvm_as, analyzed_args.llvm_ir_file, '-o', llvm_bc_file]) - os.remove(analyzed_args.llvm_ir_file) - rc = _mem2reg_opt(llvm_bc_file) - _fake_obj(llvm_bc_file.replace('.bc', '.o')) - else: - compiler = 'gfortran' - rc = mx.run([compiler] + args, nonZeroIsFatal=False) - - return rc - -def cpp(args): - _log('fastr:c++', args) - compiler = None - sulong = _sulong() - if sulong: - analyzed_args = _analyze_args(args) - rc = 0 - if analyzed_args.is_link: - rc = _create_bc_lib(args) - else: - if _is_linux(): - rc = sulong.dragonEggGPP(analyzed_args.compile_args) - elif _is_darwin(): - rc = compileWithClangPP(analyzed_args.compile_args) - if rc == 0: - if analyzed_args.llvm_ir_file: - rc = compileWithClangPP(analyzed_args.emit_llvm_args) - else: - mx.abort('unsupported platform') - if rc == 0 and not analyzed_args.is_link and analyzed_args.llvm_ir_file: - rc = _mem2reg_opt(analyzed_args.llvm_ir_file) - _fake_obj(analyzed_args.llvm_ir_file.replace('.bc', '.o')) - else: - compiler = 'g++' - rc = mx.run([compiler] + args, nonZeroIsFatal=False) - - return rc - -def cppcpp(args): - '''C++ pre-preprocessor''' - _log('fastr:cpp', args) - rc = mx.run(['cpp'] + args) - return rc - -def _mem2reg_opt(llvm_ir_file): - _log('mem2reg', llvm_ir_file) - filename = os.path.splitext(llvm_ir_file)[0] - ext = os.path.splitext(llvm_ir_file)[1] - opt_filename = filename + '.opt' + ext - rc = _sulong().opt(['-mem2reg', llvm_ir_file, '-o', opt_filename]) - if rc == 0: - os.rename(opt_filename, llvm_ir_file) - return rc - -def _fake_obj(name): - '''create an empty object file to keep make happy''' -# print 'creating ' + name - open(name, 'w').close() - -def mem2reg(args): - _mem2reg_opt(args[0]) - -def _create_bc_lib(args): - i = 0 - bcfiles = [] - while i < len(args): - arg = args[i] - if arg == '-o': - # library file - i = i + 1 - lib = args[i] - else: - if '.o' in arg: - bcfiles.append(arg.replace('.o', '.bc')) - i = i + 1 - - with zipfile.ZipFile(lib, 'w') as arc: - for bcfile in bcfiles: - arc.write(bcfile, os.path.basename(bcfile).replace('.bc', '')) - return 0 - -_commands = { - 'fastr-cc' : [cc, '[options]'], - 'fastr-fc' : [fc, '[options]'], - 'fastr-c++' : [cpp, '[options]'], - 'fastr-cpp' : [cppcpp, '[options]'], - 'mem2reg' : [mem2reg, '[options]'], -}