From d7d3a21189346757151f941123b82d22f1a3c73a Mon Sep 17 00:00:00 2001 From: Mick Jordan <mick.jordan@oracle.com> Date: Wed, 19 Jul 2017 13:08:29 -0700 Subject: [PATCH] [GR-5193] Convert python llvm compiler wrappers to bash. --- .../r/ffi/impl/llvm/TruffleLLVM_DLL.java | 26 +- .../fficall/src/truffle_llvm/README.md | 2 +- .../fficall/src/truffle_llvm/llvm_dummy.c | 24 -- .../fficall/src/truffle_llvm/llvm_dummy.f | 24 -- com.oracle.truffle.r.native/gnur/edLLVM | 4 +- .../llvm_tools/llvm-c++ | 29 +- .../llvm_tools/llvm-cc | 32 ++- .../llvm_tools/llvm-fc | 55 ++-- .../llvm_tools/llvm-helper | 160 +++++++++++ com.oracle.truffle.r.native/run/Makefile | 3 + .../run/edMakeconf.etc.llvm | 15 +- documentation/dev/truffle_llvm_ffi.md | 28 +- mx.fastr/compilers/fastr-c++ | 47 ---- mx.fastr/compilers/have_sulong | 46 ---- mx.fastr/mx_fastr.py | 2 - mx.fastr/mx_fastr_compile.py | 254 ------------------ 16 files changed, 278 insertions(+), 473 deletions(-) delete mode 100644 com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.c delete mode 100644 com.oracle.truffle.r.native/fficall/src/truffle_llvm/llvm_dummy.f rename mx.fastr/compilers/fastr-cc => com.oracle.truffle.r.native/llvm_tools/llvm-c++ (66%) rename mx.fastr/compilers/fastr-cpp => com.oracle.truffle.r.native/llvm_tools/llvm-cc (66%) rename mx.fastr/compilers/fastr-fc => com.oracle.truffle.r.native/llvm_tools/llvm-fc (57%) create mode 100644 com.oracle.truffle.r.native/llvm_tools/llvm-helper delete mode 100755 mx.fastr/compilers/fastr-c++ delete mode 100755 mx.fastr/compilers/have_sulong delete mode 100644 mx.fastr/mx_fastr_compile.py 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 21ba0f7cf6..40b50efaff 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 8ed7f64889..3b2ad0add5 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 4ad1b6b8d8..0000000000 --- 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 6c4e6cee29..0000000000 --- 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 8b3e2a29d2..4cefc6d925 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 30f313e3a2..6708749372 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 26444e34c0..69ddd766c9 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 741eacb49c..1cbd628818 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 0000000000..058eb34e7c --- /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 b874c77c38..b793c3585c 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 cb70e3626b..b079665f85 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 61dead5a44..c0cbb908c0 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 940ad0e0fe..0000000000 --- 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 96ff8288a7..0000000000 --- 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 6f42889ae2..5431374372 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 e7b0cb1032..0000000000 --- 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]'], -} -- GitLab