From 97ebcd23682443b93881f8d0047fd784899cfda7 Mon Sep 17 00:00:00 2001 From: Yu Kobayashi Date: Thu, 9 Apr 2020 04:58:15 +0900 Subject: [PATCH 1/3] LLVM full optimization --- llvm/pom.xml | 3 + llvm/samples/polly/MatMulBenchmark.java | 27 ++-- llvm/samples/polly/pom.xml | 2 +- .../java/org/bytedeco/llvm/presets/LLVM.java | 2 +- llvm/src/main/native/JavaCPPLLVMHelper.h | 143 ++++++++++++++++++ 5 files changed, 160 insertions(+), 17 deletions(-) create mode 100644 llvm/src/main/native/JavaCPPLLVMHelper.h diff --git a/llvm/pom.xml b/llvm/pom.xml index af831f05dc5..fca55162c67 100644 --- a/llvm/pom.xml +++ b/llvm/pom.xml @@ -32,6 +32,9 @@ org.bytedeco javacpp + + ${basedir}/src/main/native/ + maven-jar-plugin diff --git a/llvm/samples/polly/MatMulBenchmark.java b/llvm/samples/polly/MatMulBenchmark.java index ae917ef986d..5e2e5bac2e5 100644 --- a/llvm/samples/polly/MatMulBenchmark.java +++ b/llvm/samples/polly/MatMulBenchmark.java @@ -15,9 +15,6 @@ * * If you set usePollyParallel, you may have to modify the file name of LLVMLoadLibraryPermanently(). * - * Warning: Because it does not optimize for AVX, etc, this code is slower than this: - * clang -O3 -march=native -mllvm -polly -mllvm -polly-vectorizer=stripmine - * * Note: Instead of JNA, to obtain maximum performance, FunctionPointer should be used as shown here: * https://github.com/bytedeco/javacpp/blob/master/src/test/java/org/bytedeco/javacpp/PointerTest.java * @@ -29,6 +26,7 @@ public class MatMulBenchmark { static final boolean usePollyParallel = false; static final boolean printResult = false; + static final BytePointer cpu = LLVMGetHostCPUName(); static LLVMTypeRef llvmVoidType; static LLVMTypeRef llvmInt32Type; static LLVMTypeRef llvmFloatType; @@ -101,8 +99,8 @@ static void benchmarkLLVM(float[] a, float[] b, float[] c) { LLVMExecutionEngineRef engine = new LLVMExecutionEngineRef(); try { LLVMModuleRef module = build(); - optimize(module); verify(module, false); + optimize(module); jitCompile(engine, module); long fnAddr = LLVMGetFunctionAddress(engine, "matmul"); @@ -237,15 +235,14 @@ static LLVMModuleRef build() { } static void optimize(LLVMModuleRef module) { - LLVMPassManagerBuilderRef pmb = LLVMPassManagerBuilderCreate(); - LLVMPassManagerBuilderSetOptLevel(pmb, 3); - LLVMPassManagerRef pass = LLVMCreatePassManager(); - LLVMPassManagerBuilderPopulateModulePassManager(pmb, pass); - - LLVMRunPassManager(pass, module); - - LLVMDisposePassManager(pass); - LLVMPassManagerBuilderDispose(pmb); + BytePointer error = new BytePointer((Pointer) null); + try { + if (JavaCPPLLVMOptimizeModule(module, cpu, 3, 0, error) != 0) { + throw new RuntimeException(error.getString()); + } + } finally { + LLVMDisposeMessage(error); + } } static void verify(LLVMModuleRef module, boolean dumpModule) { @@ -254,7 +251,7 @@ static void verify(LLVMModuleRef module, boolean dumpModule) { if (dumpModule) { LLVMDumpModule(module); } - if (LLVMVerifyModule(module, LLVMAbortProcessAction, error) != 0) { + if (LLVMVerifyModule(module, LLVMPrintMessageAction, error) != 0) { throw new RuntimeException(error.getString()); } } finally { @@ -265,7 +262,7 @@ static void verify(LLVMModuleRef module, boolean dumpModule) { static void jitCompile(LLVMExecutionEngineRef engine, LLVMModuleRef module) { BytePointer error = new BytePointer((Pointer) null); try { - if (LLVMCreateJITCompilerForModule(engine, module, 3, error) != 0) { + if (JavaCPPLLVMCreateOptimizedJITCompilerForModule(engine, module, cpu, 3, error) != 0) { throw new RuntimeException(error.getString()); } } finally { diff --git a/llvm/samples/polly/pom.xml b/llvm/samples/polly/pom.xml index c1a4feb91a8..147596eaf03 100644 --- a/llvm/samples/polly/pom.xml +++ b/llvm/samples/polly/pom.xml @@ -13,7 +13,7 @@ org.bytedeco llvm-platform - 10.0.0-1.5.3 + 10.0.0-1.5.4-SNAPSHOT net.java.dev.jna diff --git a/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java b/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java index 437b66c972d..8ef84dc84c2 100644 --- a/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java +++ b/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java @@ -35,7 +35,7 @@ "", "", "", "", "", "", "", "", "", "", "", "", "", "", - ""}, + "", ""}, compiler = "cpp14", link = {"LLVM-10", "LTO@.10", "LLVMPolly"}), @Platform(value = {"macosx", "windows"}, link = {"LLVM", "LTO", "Polly", "PollyISL", "PollyPPCG"})}) public class LLVM implements InfoMapper { diff --git a/llvm/src/main/native/JavaCPPLLVMHelper.h b/llvm/src/main/native/JavaCPPLLVMHelper.h new file mode 100644 index 00000000000..08ea2f170a4 --- /dev/null +++ b/llvm/src/main/native/JavaCPPLLVMHelper.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2020 Yu Kobayashi + * + * Licensed either under the Apache License, Version 2.0, or (at your option) + * under the terms of the GNU General Public License as published by + * the Free Software Foundation (subject to the "Classpath" exception), + * either version 2, or any later version (collectively, the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/ + * http://www.gnu.org/software/classpath/license.html + * + * or as provided in the LICENSE.txt file that accompanied this code. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JAVACPP_LLVM_HELPER_H +#define JAVACPP_LLVM_HELPER_H + +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/IR/Verifier.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Pass.h" +#include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm-c/Types.h" + +using namespace llvm; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This function does the standard LLVM optimization. + * This function is based on main() of llvm/tools/opt/opt.cpp. + * Use LLVMGetHostCPUName() for the cpu argument. + */ +LLVMBool JavaCPPLLVMOptimizeModule( + LLVMModuleRef moduleRef, + const char* cpu, + unsigned optLevel, + unsigned sizeLevel, + char** outError +) { + Module *module = unwrap(moduleRef); + + std::string error; + EngineBuilder engineBuilder; + TargetMachine *machine = engineBuilder + .setMCPU(cpu) + .setErrorStr(&error) + .selectTarget(); + if (machine == nullptr) { + *outError = strdup(error.c_str()); + return 1; + } + + module->setTargetTriple(machine->getTargetTriple().str()); + module->setDataLayout(machine->createDataLayout()); + + legacy::PassManager passes; + passes.add(new TargetLibraryInfoWrapperPass(machine->getTargetTriple())); + passes.add(createTargetTransformInfoWrapperPass(machine->getTargetIRAnalysis())); + + legacy::FunctionPassManager fnPasses(module); + fnPasses.add(createTargetTransformInfoWrapperPass(machine->getTargetIRAnalysis())); + + // AddOptimizationPasses + PassManagerBuilder builder1; + builder1.OptLevel = optLevel; + builder1.SizeLevel = sizeLevel; + builder1.Inliner = createFunctionInliningPass(optLevel, sizeLevel, false); + builder1.LoopVectorize = optLevel > 1 && sizeLevel < 2; + builder1.SLPVectorize = optLevel > 1 && sizeLevel < 2; + machine->adjustPassManager(builder1); + builder1.populateFunctionPassManager(fnPasses); + builder1.populateModulePassManager(passes); + + // AddStandardLinkPasses + PassManagerBuilder builder2; + builder2.VerifyInput = true; + builder2.Inliner = createFunctionInliningPass(); + builder2.populateLTOPassManager(passes); + + fnPasses.doInitialization(); + for (Function &func : *module) { + fnPasses.run(func); + } + fnPasses.doFinalization(); + + passes.add(createVerifierPass()); + passes.run(*module); + + return 0; +} + +/** + * This function is similar to LLVMCreateJITCompilerForModule() but does CPU specific optimization. + * Use LLVMGetHostCPUName() for the cpu argument. + */ +LLVMBool JavaCPPLLVMCreateOptimizedJITCompilerForModule( + LLVMExecutionEngineRef *outJIT, + LLVMModuleRef moduleRef, + const char* cpu, + unsigned optLevel, + char **outError +) { + std::string error; + EngineBuilder engineBuilder(std::unique_ptr(unwrap(moduleRef))); + ExecutionEngine *ee = engineBuilder + .setEngineKind(EngineKind::JIT) + .setMCPU(cpu) + .setOptLevel(static_cast(optLevel)) + .setErrorStr(&error) + .create(); + if (ee == nullptr) { + *outError = strdup(error.c_str()); + return 1; + } + ee->finalizeObject(); + *outJIT = wrap(ee); + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif From d65d12761a04a86319174d37beb0f0745068b9d5 Mon Sep 17 00:00:00 2001 From: Samuel Audet Date: Thu, 16 Apr 2020 21:49:52 +0900 Subject: [PATCH 2/3] Objectify a bit the custom functions --- llvm/pom.xml | 3 - llvm/samples/polly/MatMulBenchmark.java | 21 ++--- .../java/org/bytedeco/llvm/global/LLVM.java | 82 ++++++++++++++++++- .../java/org/bytedeco/llvm/presets/LLVM.java | 2 +- .../bytedeco/llvm/include/FullOptimization.h} | 31 ++----- 5 files changed, 95 insertions(+), 44 deletions(-) rename llvm/src/main/{native/JavaCPPLLVMHelper.h => resources/org/bytedeco/llvm/include/FullOptimization.h} (89%) diff --git a/llvm/pom.xml b/llvm/pom.xml index fca55162c67..af831f05dc5 100644 --- a/llvm/pom.xml +++ b/llvm/pom.xml @@ -32,9 +32,6 @@ org.bytedeco javacpp - - ${basedir}/src/main/native/ - maven-jar-plugin diff --git a/llvm/samples/polly/MatMulBenchmark.java b/llvm/samples/polly/MatMulBenchmark.java index 5e2e5bac2e5..e2e8e4f3803 100644 --- a/llvm/samples/polly/MatMulBenchmark.java +++ b/llvm/samples/polly/MatMulBenchmark.java @@ -15,6 +15,9 @@ * * If you set usePollyParallel, you may have to modify the file name of LLVMLoadLibraryPermanently(). * + * Note: This code is equivalent to this: + * clang -O3 -march=native -mllvm -polly -mllvm -polly-vectorizer=stripmine + * * Note: Instead of JNA, to obtain maximum performance, FunctionPointer should be used as shown here: * https://github.com/bytedeco/javacpp/blob/master/src/test/java/org/bytedeco/javacpp/PointerTest.java * @@ -235,14 +238,7 @@ static LLVMModuleRef build() { } static void optimize(LLVMModuleRef module) { - BytePointer error = new BytePointer((Pointer) null); - try { - if (JavaCPPLLVMOptimizeModule(module, cpu, 3, 0, error) != 0) { - throw new RuntimeException(error.getString()); - } - } finally { - LLVMDisposeMessage(error); - } + optimizeModule(module, cpu, 3, 0); } static void verify(LLVMModuleRef module, boolean dumpModule) { @@ -260,14 +256,7 @@ static void verify(LLVMModuleRef module, boolean dumpModule) { } static void jitCompile(LLVMExecutionEngineRef engine, LLVMModuleRef module) { - BytePointer error = new BytePointer((Pointer) null); - try { - if (JavaCPPLLVMCreateOptimizedJITCompilerForModule(engine, module, cpu, 3, error) != 0) { - throw new RuntimeException(error.getString()); - } - } finally { - LLVMDisposeMessage(error); - } + createOptimizedJITCompilerForModule(engine, module, cpu, 3); } static LLVMValueRef toConstInt(int v) { diff --git a/llvm/src/gen/java/org/bytedeco/llvm/global/LLVM.java b/llvm/src/gen/java/org/bytedeco/llvm/global/LLVM.java index 7c2901607f5..91b11c584b1 100644 --- a/llvm/src/gen/java/org/bytedeco/llvm/global/LLVM.java +++ b/llvm/src/gen/java/org/bytedeco/llvm/global/LLVM.java @@ -1,4 +1,4 @@ -// Targeted by JavaCPP version 1.5.3: DO NOT EDIT THIS FILE +// Targeted by JavaCPP version 1.5.4-SNAPSHOT: DO NOT EDIT THIS FILE package org.bytedeco.llvm.global; @@ -10533,4 +10533,84 @@ public static native void LLVMAddScalarReplAggregatesPassWithThreshold(LLVMPassM // #endif +// Parsed from + +/* + * Copyright (C) 2020 Yu Kobayashi + * + * Licensed either under the Apache License, Version 2.0, or (at your option) + * under the terms of the GNU General Public License as published by + * the Free Software Foundation (subject to the "Classpath" exception), + * either version 2, or any later version (collectively, the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/ + * http://www.gnu.org/software/classpath/license.html + * + * or as provided in the LICENSE.txt file that accompanied this code. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #ifndef FULL_OPTIMIZATION_H +// #define FULL_OPTIMIZATION_H + +// #include "llvm/ExecutionEngine/ExecutionEngine.h" +// #include "llvm/Target/TargetMachine.h" +// #include "llvm/Transforms/IPO.h" +// #include "llvm/Transforms/IPO/PassManagerBuilder.h" +// #include "llvm/IR/Verifier.h" +// #include "llvm/IR/LegacyPassManager.h" +// #include "llvm/CodeGen/TargetPassConfig.h" +// #include "llvm/Support/TargetRegistry.h" +// #include "llvm/Analysis/TargetLibraryInfo.h" +// #include "llvm/Analysis/TargetTransformInfo.h" +// #include "llvm/MC/SubtargetFeature.h" +// #include "llvm/Pass.h" +// #include "llvm-c/Transforms/PassManagerBuilder.h" +// #include "llvm-c/Types.h" + +/** + * This function does the standard LLVM optimization. + * This function is based on main() of llvm/tools/opt/opt.cpp. + * Use LLVMGetHostCPUName() for the cpu argument. + */ +public static native void optimizeModule( + LLVMModuleRef moduleRef, + @Cast("const char*") BytePointer cpu, + @Cast("unsigned") int optLevel, + @Cast("unsigned") int sizeLevel +); +public static native void optimizeModule( + LLVMModuleRef moduleRef, + String cpu, + @Cast("unsigned") int optLevel, + @Cast("unsigned") int sizeLevel +); + +/** + * This function is similar to LLVMCreateJITCompilerForModule() but does CPU specific optimization. + * Use LLVMGetHostCPUName() for the cpu argument. + */ +public static native void createOptimizedJITCompilerForModule( + @ByPtrPtr LLVMExecutionEngineRef outJIT, + LLVMModuleRef moduleRef, + @Cast("const char*") BytePointer cpu, + @Cast("unsigned") int optLevel +); +public static native void createOptimizedJITCompilerForModule( + @Cast("LLVMExecutionEngineRef*") PointerPointer outJIT, + LLVMModuleRef moduleRef, + String cpu, + @Cast("unsigned") int optLevel +); + +// #endif + + } diff --git a/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java b/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java index 8ef84dc84c2..443d0195cb0 100644 --- a/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java +++ b/llvm/src/main/java/org/bytedeco/llvm/presets/LLVM.java @@ -35,7 +35,7 @@ "", "", "", "", "", "", "", "", "", "", "", "", "", "", - "", ""}, + "", ""}, compiler = "cpp14", link = {"LLVM-10", "LTO@.10", "LLVMPolly"}), @Platform(value = {"macosx", "windows"}, link = {"LLVM", "LTO", "Polly", "PollyISL", "PollyPPCG"})}) public class LLVM implements InfoMapper { diff --git a/llvm/src/main/native/JavaCPPLLVMHelper.h b/llvm/src/main/resources/org/bytedeco/llvm/include/FullOptimization.h similarity index 89% rename from llvm/src/main/native/JavaCPPLLVMHelper.h rename to llvm/src/main/resources/org/bytedeco/llvm/include/FullOptimization.h index 08ea2f170a4..e120ca61c80 100644 --- a/llvm/src/main/native/JavaCPPLLVMHelper.h +++ b/llvm/src/main/resources/org/bytedeco/llvm/include/FullOptimization.h @@ -20,8 +20,8 @@ * limitations under the License. */ -#ifndef JAVACPP_LLVM_HELPER_H -#define JAVACPP_LLVM_HELPER_H +#ifndef FULL_OPTIMIZATION_H +#define FULL_OPTIMIZATION_H #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/Target/TargetMachine.h" @@ -40,21 +40,16 @@ using namespace llvm; -#ifdef __cplusplus -extern "C" { -#endif - /** * This function does the standard LLVM optimization. * This function is based on main() of llvm/tools/opt/opt.cpp. * Use LLVMGetHostCPUName() for the cpu argument. */ -LLVMBool JavaCPPLLVMOptimizeModule( +void optimizeModule( LLVMModuleRef moduleRef, const char* cpu, unsigned optLevel, - unsigned sizeLevel, - char** outError + unsigned sizeLevel ) { Module *module = unwrap(moduleRef); @@ -65,8 +60,7 @@ LLVMBool JavaCPPLLVMOptimizeModule( .setErrorStr(&error) .selectTarget(); if (machine == nullptr) { - *outError = strdup(error.c_str()); - return 1; + throw std::runtime_error(error); } module->setTargetTriple(machine->getTargetTriple().str()); @@ -104,20 +98,17 @@ LLVMBool JavaCPPLLVMOptimizeModule( passes.add(createVerifierPass()); passes.run(*module); - - return 0; } /** * This function is similar to LLVMCreateJITCompilerForModule() but does CPU specific optimization. * Use LLVMGetHostCPUName() for the cpu argument. */ -LLVMBool JavaCPPLLVMCreateOptimizedJITCompilerForModule( +void createOptimizedJITCompilerForModule( LLVMExecutionEngineRef *outJIT, LLVMModuleRef moduleRef, const char* cpu, - unsigned optLevel, - char **outError + unsigned optLevel ) { std::string error; EngineBuilder engineBuilder(std::unique_ptr(unwrap(moduleRef))); @@ -128,16 +119,10 @@ LLVMBool JavaCPPLLVMCreateOptimizedJITCompilerForModule( .setErrorStr(&error) .create(); if (ee == nullptr) { - *outError = strdup(error.c_str()); - return 1; + throw std::runtime_error(error); } ee->finalizeObject(); *outJIT = wrap(ee); - return 0; } -#ifdef __cplusplus -} -#endif - #endif From 1cdd618dbeafd2e5734531210d8db5d24e9fc27e Mon Sep 17 00:00:00 2001 From: Samuel Audet Date: Mon, 20 Apr 2020 14:30:45 +0900 Subject: [PATCH 3/3] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 972abd2b54e..0b1a5db1a34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ + * Add `FullOptimization.h` allowing users to fully optimize LLVM modules ([pull #869](https://github.com/bytedeco/javacpp-presets/pull/869)) + ### April 14, 2020 version 1.5.3 * Add presets for the new `intensity_transform` and `rapid` modules of OpenCV * Add support for Polly optimizer to presets for LLVM ([pull #864](https://github.com/bytedeco/javacpp-presets/pull/864))