1d6efb6fcSMehdi Amini //===- Invoke.cpp ------------------------------------*- C++ -*-===// 2d6efb6fcSMehdi Amini // 3d6efb6fcSMehdi Amini // This file is licensed under the Apache License v2.0 with LLVM Exceptions. 4d6efb6fcSMehdi Amini // See https://llvm.org/LICENSE.txt for license information. 5d6efb6fcSMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6d6efb6fcSMehdi Amini // 7d6efb6fcSMehdi Amini //===----------------------------------------------------------------------===// 8d6efb6fcSMehdi Amini 9abc362a1SJakub Kuderski #include "mlir/Conversion/ArithToLLVM/ArithToLLVM.h" 105a7b9194SRiver Riddle #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVMPass.h" 1175e5f0aaSAlex Zinenko #include "mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h" 128b58ab8cSAlex Zinenko #include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h" 13d6efb6fcSMehdi Amini #include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h" 14d6efb6fcSMehdi Amini #include "mlir/Conversion/VectorToSCF/VectorToSCF.h" 1536550692SRiver Riddle #include "mlir/Dialect/Func/IR/FuncOps.h" 16d6efb6fcSMehdi Amini #include "mlir/Dialect/Linalg/Passes.h" 17d6efb6fcSMehdi Amini #include "mlir/ExecutionEngine/CRunnerUtils.h" 18d6efb6fcSMehdi Amini #include "mlir/ExecutionEngine/ExecutionEngine.h" 199680ea5cSMehdi Amini #include "mlir/ExecutionEngine/MemRefUtils.h" 20d6efb6fcSMehdi Amini #include "mlir/ExecutionEngine/RunnerUtils.h" 21d6efb6fcSMehdi Amini #include "mlir/IR/MLIRContext.h" 22d6efb6fcSMehdi Amini #include "mlir/InitAllDialects.h" 239eaff423SRiver Riddle #include "mlir/Parser/Parser.h" 24d6efb6fcSMehdi Amini #include "mlir/Pass/PassManager.h" 250e9523efSSergio Afonso #include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h" 2619db802eSAlex Zinenko #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" 2719db802eSAlex Zinenko #include "mlir/Target/LLVMIR/Export.h" 28d6efb6fcSMehdi Amini #include "llvm/Support/TargetSelect.h" 29d6efb6fcSMehdi Amini #include "llvm/Support/raw_ostream.h" 30d6efb6fcSMehdi Amini 31d6efb6fcSMehdi Amini #include "gmock/gmock.h" 32d6efb6fcSMehdi Amini 33ca98e0ddSRainer Orth // SPARC currently lacks JIT support. 34ca98e0ddSRainer Orth #ifdef __sparc__ 35ca98e0ddSRainer Orth #define SKIP_WITHOUT_JIT(x) DISABLED_##x 36ca98e0ddSRainer Orth #else 37ca98e0ddSRainer Orth #define SKIP_WITHOUT_JIT(x) x 38ca98e0ddSRainer Orth #endif 39ca98e0ddSRainer Orth 40d6efb6fcSMehdi Amini using namespace mlir; 41d6efb6fcSMehdi Amini 42dc3b9365SAlexandre Ganea // The JIT isn't supported on Windows at that time 43dc3b9365SAlexandre Ganea #ifndef _WIN32 44dc3b9365SAlexandre Ganea 45d6efb6fcSMehdi Amini static struct LLVMInitializer { 46d6efb6fcSMehdi Amini LLVMInitializer() { 47d6efb6fcSMehdi Amini llvm::InitializeNativeTarget(); 48d6efb6fcSMehdi Amini llvm::InitializeNativeTargetAsmPrinter(); 49d6efb6fcSMehdi Amini } 50d6efb6fcSMehdi Amini } initializer; 51d6efb6fcSMehdi Amini 52d6efb6fcSMehdi Amini /// Simple conversion pipeline for the purpose of testing sources written in 53d6efb6fcSMehdi Amini /// dialects lowering to LLVM Dialect. 54d6efb6fcSMehdi Amini static LogicalResult lowerToLLVMDialect(ModuleOp module) { 5594a30928Srkayaith PassManager pm(module->getName()); 56cb4ccd38SQuentin Colombet pm.addPass(mlir::createFinalizeMemRefToLLVMConversionPass()); 57abc362a1SJakub Kuderski pm.addNestedPass<func::FuncOp>(mlir::createArithToLLVMConversionPass()); 585a7b9194SRiver Riddle pm.addPass(mlir::createConvertFuncToLLVMPass()); 598b58ab8cSAlex Zinenko pm.addPass(mlir::createReconcileUnrealizedCastsPass()); 60d6efb6fcSMehdi Amini return pm.run(module); 61d6efb6fcSMehdi Amini } 62d6efb6fcSMehdi Amini 63ca98e0ddSRainer Orth TEST(MLIRExecutionEngine, SKIP_WITHOUT_JIT(AddInteger)) { 64*0d9dc421SJonas Paulsson #ifdef __s390__ 65*0d9dc421SJonas Paulsson std::string moduleStr = R"mlir( 66*0d9dc421SJonas Paulsson func.func @foo(%arg0 : i32 {llvm.signext}) -> (i32 {llvm.signext}) attributes { llvm.emit_c_interface } { 67*0d9dc421SJonas Paulsson %res = arith.addi %arg0, %arg0 : i32 68*0d9dc421SJonas Paulsson return %res : i32 69*0d9dc421SJonas Paulsson } 70*0d9dc421SJonas Paulsson )mlir"; 71*0d9dc421SJonas Paulsson #else 72d6efb6fcSMehdi Amini std::string moduleStr = R"mlir( 7363237cddSRiver Riddle func.func @foo(%arg0 : i32) -> i32 attributes { llvm.emit_c_interface } { 74a54f4eaeSMogball %res = arith.addi %arg0, %arg0 : i32 75d6efb6fcSMehdi Amini return %res : i32 76d6efb6fcSMehdi Amini } 77d6efb6fcSMehdi Amini )mlir"; 78*0d9dc421SJonas Paulsson #endif 79b77bac05SAlex Zinenko DialectRegistry registry; 80b77bac05SAlex Zinenko registerAllDialects(registry); 810e9523efSSergio Afonso registerBuiltinDialectTranslation(registry); 82b77bac05SAlex Zinenko registerLLVMDialectTranslation(registry); 83b77bac05SAlex Zinenko MLIRContext context(registry); 84dfaadf6bSChristian Sigg OwningOpRef<ModuleOp> module = 85dfaadf6bSChristian Sigg parseSourceString<ModuleOp>(moduleStr, &context); 86d6efb6fcSMehdi Amini ASSERT_TRUE(!!module); 87d6efb6fcSMehdi Amini ASSERT_TRUE(succeeded(lowerToLLVMDialect(*module))); 88d6efb6fcSMehdi Amini auto jitOrError = ExecutionEngine::create(*module); 89d6efb6fcSMehdi Amini ASSERT_TRUE(!!jitOrError); 90d6efb6fcSMehdi Amini std::unique_ptr<ExecutionEngine> jit = std::move(jitOrError.get()); 91d6efb6fcSMehdi Amini // The result of the function must be passed as output argument. 92d6efb6fcSMehdi Amini int result = 0; 93d6efb6fcSMehdi Amini llvm::Error error = 94d6efb6fcSMehdi Amini jit->invoke("foo", 42, ExecutionEngine::Result<int>(result)); 95d6efb6fcSMehdi Amini ASSERT_TRUE(!error); 96d6efb6fcSMehdi Amini ASSERT_EQ(result, 42 + 42); 97d6efb6fcSMehdi Amini } 98d6efb6fcSMehdi Amini 99ca98e0ddSRainer Orth TEST(MLIRExecutionEngine, SKIP_WITHOUT_JIT(SubtractFloat)) { 100d6efb6fcSMehdi Amini std::string moduleStr = R"mlir( 10163237cddSRiver Riddle func.func @foo(%arg0 : f32, %arg1 : f32) -> f32 attributes { llvm.emit_c_interface } { 102a54f4eaeSMogball %res = arith.subf %arg0, %arg1 : f32 103d6efb6fcSMehdi Amini return %res : f32 104d6efb6fcSMehdi Amini } 105d6efb6fcSMehdi Amini )mlir"; 106b77bac05SAlex Zinenko DialectRegistry registry; 107b77bac05SAlex Zinenko registerAllDialects(registry); 1080e9523efSSergio Afonso registerBuiltinDialectTranslation(registry); 109b77bac05SAlex Zinenko registerLLVMDialectTranslation(registry); 110b77bac05SAlex Zinenko MLIRContext context(registry); 111dfaadf6bSChristian Sigg OwningOpRef<ModuleOp> module = 112dfaadf6bSChristian Sigg parseSourceString<ModuleOp>(moduleStr, &context); 113d6efb6fcSMehdi Amini ASSERT_TRUE(!!module); 114d6efb6fcSMehdi Amini ASSERT_TRUE(succeeded(lowerToLLVMDialect(*module))); 115d6efb6fcSMehdi Amini auto jitOrError = ExecutionEngine::create(*module); 116d6efb6fcSMehdi Amini ASSERT_TRUE(!!jitOrError); 117d6efb6fcSMehdi Amini std::unique_ptr<ExecutionEngine> jit = std::move(jitOrError.get()); 118d6efb6fcSMehdi Amini // The result of the function must be passed as output argument. 119d6efb6fcSMehdi Amini float result = -1; 120d6efb6fcSMehdi Amini llvm::Error error = 121d6efb6fcSMehdi Amini jit->invoke("foo", 43.0f, 1.0f, ExecutionEngine::result(result)); 122d6efb6fcSMehdi Amini ASSERT_TRUE(!error); 123d6efb6fcSMehdi Amini ASSERT_EQ(result, 42.f); 124d6efb6fcSMehdi Amini } 125d6efb6fcSMehdi Amini 126ca98e0ddSRainer Orth TEST(NativeMemRefJit, SKIP_WITHOUT_JIT(ZeroRankMemref)) { 12702b6fb21SMehdi Amini OwningMemRef<float, 0> a({}); 12802b6fb21SMehdi Amini a[{}] = 42.; 12902b6fb21SMehdi Amini ASSERT_EQ(*a->data, 42); 13002b6fb21SMehdi Amini a[{}] = 0; 1319680ea5cSMehdi Amini std::string moduleStr = R"mlir( 13263237cddSRiver Riddle func.func @zero_ranked(%arg0 : memref<f32>) attributes { llvm.emit_c_interface } { 133a54f4eaeSMogball %cst42 = arith.constant 42.0 : f32 134e2310704SJulian Gross memref.store %cst42, %arg0[] : memref<f32> 1359680ea5cSMehdi Amini return 1369680ea5cSMehdi Amini } 1379680ea5cSMehdi Amini )mlir"; 138b77bac05SAlex Zinenko DialectRegistry registry; 139b77bac05SAlex Zinenko registerAllDialects(registry); 1400e9523efSSergio Afonso registerBuiltinDialectTranslation(registry); 141b77bac05SAlex Zinenko registerLLVMDialectTranslation(registry); 142b77bac05SAlex Zinenko MLIRContext context(registry); 143dfaadf6bSChristian Sigg auto module = parseSourceString<ModuleOp>(moduleStr, &context); 1449680ea5cSMehdi Amini ASSERT_TRUE(!!module); 1459680ea5cSMehdi Amini ASSERT_TRUE(succeeded(lowerToLLVMDialect(*module))); 1469680ea5cSMehdi Amini auto jitOrError = ExecutionEngine::create(*module); 1479680ea5cSMehdi Amini ASSERT_TRUE(!!jitOrError); 1489680ea5cSMehdi Amini auto jit = std::move(jitOrError.get()); 1499680ea5cSMehdi Amini 15002b6fb21SMehdi Amini llvm::Error error = jit->invoke("zero_ranked", &*a); 1519680ea5cSMehdi Amini ASSERT_TRUE(!error); 15202b6fb21SMehdi Amini EXPECT_EQ((a[{}]), 42.); 15302b6fb21SMehdi Amini for (float &elt : *a) 15402b6fb21SMehdi Amini EXPECT_EQ(&elt, &(a[{}])); 1559680ea5cSMehdi Amini } 1569680ea5cSMehdi Amini 157ca98e0ddSRainer Orth TEST(NativeMemRefJit, SKIP_WITHOUT_JIT(RankOneMemref)) { 1589680ea5cSMehdi Amini int64_t shape[] = {9}; 15902b6fb21SMehdi Amini OwningMemRef<float, 1> a(shape); 1609680ea5cSMehdi Amini int count = 1; 16102b6fb21SMehdi Amini for (float &elt : *a) { 16202b6fb21SMehdi Amini EXPECT_EQ(&elt, &(a[{count - 1}])); 1639680ea5cSMehdi Amini elt = count++; 1649680ea5cSMehdi Amini } 1659680ea5cSMehdi Amini 1669680ea5cSMehdi Amini std::string moduleStr = R"mlir( 16763237cddSRiver Riddle func.func @one_ranked(%arg0 : memref<?xf32>) attributes { llvm.emit_c_interface } { 168a54f4eaeSMogball %cst42 = arith.constant 42.0 : f32 169a54f4eaeSMogball %cst5 = arith.constant 5 : index 170e2310704SJulian Gross memref.store %cst42, %arg0[%cst5] : memref<?xf32> 1719680ea5cSMehdi Amini return 1729680ea5cSMehdi Amini } 1739680ea5cSMehdi Amini )mlir"; 174b77bac05SAlex Zinenko DialectRegistry registry; 175b77bac05SAlex Zinenko registerAllDialects(registry); 1760e9523efSSergio Afonso registerBuiltinDialectTranslation(registry); 177b77bac05SAlex Zinenko registerLLVMDialectTranslation(registry); 178b77bac05SAlex Zinenko MLIRContext context(registry); 179dfaadf6bSChristian Sigg auto module = parseSourceString<ModuleOp>(moduleStr, &context); 1809680ea5cSMehdi Amini ASSERT_TRUE(!!module); 1819680ea5cSMehdi Amini ASSERT_TRUE(succeeded(lowerToLLVMDialect(*module))); 1829680ea5cSMehdi Amini auto jitOrError = ExecutionEngine::create(*module); 1839680ea5cSMehdi Amini ASSERT_TRUE(!!jitOrError); 1849680ea5cSMehdi Amini auto jit = std::move(jitOrError.get()); 1859680ea5cSMehdi Amini 18602b6fb21SMehdi Amini llvm::Error error = jit->invoke("one_ranked", &*a); 1879680ea5cSMehdi Amini ASSERT_TRUE(!error); 1889680ea5cSMehdi Amini count = 1; 18902b6fb21SMehdi Amini for (float &elt : *a) { 1909680ea5cSMehdi Amini if (count == 6) 1919680ea5cSMehdi Amini EXPECT_EQ(elt, 42.); 1929680ea5cSMehdi Amini else 1939680ea5cSMehdi Amini EXPECT_EQ(elt, count); 1949680ea5cSMehdi Amini count++; 1959680ea5cSMehdi Amini } 1969680ea5cSMehdi Amini } 1979680ea5cSMehdi Amini 198ca98e0ddSRainer Orth TEST(NativeMemRefJit, SKIP_WITHOUT_JIT(BasicMemref)) { 19902b6fb21SMehdi Amini constexpr int k = 3; 20002b6fb21SMehdi Amini constexpr int m = 7; 2019680ea5cSMehdi Amini // Prepare arguments beforehand. 2029680ea5cSMehdi Amini auto init = [=](float &elt, ArrayRef<int64_t> indices) { 2039680ea5cSMehdi Amini assert(indices.size() == 2); 20402b6fb21SMehdi Amini elt = m * indices[0] + indices[1]; 2059680ea5cSMehdi Amini }; 20602b6fb21SMehdi Amini int64_t shape[] = {k, m}; 20702b6fb21SMehdi Amini int64_t shapeAlloc[] = {k + 1, m + 1}; 20802b6fb21SMehdi Amini OwningMemRef<float, 2> a(shape, shapeAlloc, init); 20902b6fb21SMehdi Amini ASSERT_EQ(a->sizes[0], k); 21002b6fb21SMehdi Amini ASSERT_EQ(a->sizes[1], m); 21102b6fb21SMehdi Amini ASSERT_EQ(a->strides[0], m + 1); 21202b6fb21SMehdi Amini ASSERT_EQ(a->strides[1], 1); 21302b6fb21SMehdi Amini for (int i = 0; i < k; ++i) { 21402b6fb21SMehdi Amini for (int j = 0; j < m; ++j) { 21502b6fb21SMehdi Amini EXPECT_EQ((a[{i, j}]), i * m + j); 21602b6fb21SMehdi Amini EXPECT_EQ(&(a[{i, j}]), &((*a)[i][j])); 21781987396SMehdi Amini } 21881987396SMehdi Amini } 2199680ea5cSMehdi Amini std::string moduleStr = R"mlir( 22063237cddSRiver Riddle func.func @rank2_memref(%arg0 : memref<?x?xf32>, %arg1 : memref<?x?xf32>) attributes { llvm.emit_c_interface } { 221a54f4eaeSMogball %x = arith.constant 2 : index 222a54f4eaeSMogball %y = arith.constant 1 : index 223a54f4eaeSMogball %cst42 = arith.constant 42.0 : f32 224e2310704SJulian Gross memref.store %cst42, %arg0[%y, %x] : memref<?x?xf32> 225e2310704SJulian Gross memref.store %cst42, %arg1[%x, %y] : memref<?x?xf32> 2269680ea5cSMehdi Amini return 2279680ea5cSMehdi Amini } 2289680ea5cSMehdi Amini )mlir"; 229b77bac05SAlex Zinenko DialectRegistry registry; 230b77bac05SAlex Zinenko registerAllDialects(registry); 2310e9523efSSergio Afonso registerBuiltinDialectTranslation(registry); 232b77bac05SAlex Zinenko registerLLVMDialectTranslation(registry); 233b77bac05SAlex Zinenko MLIRContext context(registry); 234dfaadf6bSChristian Sigg OwningOpRef<ModuleOp> module = 235dfaadf6bSChristian Sigg parseSourceString<ModuleOp>(moduleStr, &context); 2369680ea5cSMehdi Amini ASSERT_TRUE(!!module); 2379680ea5cSMehdi Amini ASSERT_TRUE(succeeded(lowerToLLVMDialect(*module))); 2389680ea5cSMehdi Amini auto jitOrError = ExecutionEngine::create(*module); 2399680ea5cSMehdi Amini ASSERT_TRUE(!!jitOrError); 2409680ea5cSMehdi Amini std::unique_ptr<ExecutionEngine> jit = std::move(jitOrError.get()); 2419680ea5cSMehdi Amini 24202b6fb21SMehdi Amini llvm::Error error = jit->invoke("rank2_memref", &*a, &*a); 2439680ea5cSMehdi Amini ASSERT_TRUE(!error); 24402b6fb21SMehdi Amini EXPECT_EQ(((*a)[1][2]), 42.); 24502b6fb21SMehdi Amini EXPECT_EQ((a[{2, 1}]), 42.); 2469680ea5cSMehdi Amini } 2479680ea5cSMehdi Amini 2489680ea5cSMehdi Amini // A helper function that will be called from the JIT 24902b6fb21SMehdi Amini static void memrefMultiply(::StridedMemRefType<float, 2> *memref, 2509680ea5cSMehdi Amini int32_t coefficient) { 2519680ea5cSMehdi Amini for (float &elt : *memref) 2529680ea5cSMehdi Amini elt *= coefficient; 2539680ea5cSMehdi Amini } 2549680ea5cSMehdi Amini 2550d70bc99SVitaly Buka // MSAN does not work with JIT. 2560d70bc99SVitaly Buka #if __has_feature(memory_sanitizer) 2570d70bc99SVitaly Buka #define MAYBE_JITCallback DISABLED_JITCallback 2580d70bc99SVitaly Buka #else 259ca98e0ddSRainer Orth #define MAYBE_JITCallback SKIP_WITHOUT_JIT(JITCallback) 2600d70bc99SVitaly Buka #endif 2610d70bc99SVitaly Buka TEST(NativeMemRefJit, MAYBE_JITCallback) { 26202b6fb21SMehdi Amini constexpr int k = 2; 26302b6fb21SMehdi Amini constexpr int m = 2; 26402b6fb21SMehdi Amini int64_t shape[] = {k, m}; 26502b6fb21SMehdi Amini int64_t shapeAlloc[] = {k + 1, m + 1}; 26602b6fb21SMehdi Amini OwningMemRef<float, 2> a(shape, shapeAlloc); 2679680ea5cSMehdi Amini int count = 1; 26802b6fb21SMehdi Amini for (float &elt : *a) 2699680ea5cSMehdi Amini elt = count++; 2709680ea5cSMehdi Amini 271*0d9dc421SJonas Paulsson #ifdef __s390__ 272*0d9dc421SJonas Paulsson std::string moduleStr = R"mlir( 273*0d9dc421SJonas Paulsson func.func private @callback(%arg0: memref<?x?xf32>, %coefficient: i32 {llvm.signext}) attributes { llvm.emit_c_interface } 274*0d9dc421SJonas Paulsson func.func @caller_for_callback(%arg0: memref<?x?xf32>, %coefficient: i32 {llvm.signext}) attributes { llvm.emit_c_interface } { 275*0d9dc421SJonas Paulsson %unranked = memref.cast %arg0: memref<?x?xf32> to memref<*xf32> 276*0d9dc421SJonas Paulsson call @callback(%arg0, %coefficient) : (memref<?x?xf32>, i32) -> () 277*0d9dc421SJonas Paulsson return 278*0d9dc421SJonas Paulsson } 279*0d9dc421SJonas Paulsson )mlir"; 280*0d9dc421SJonas Paulsson #else 2819680ea5cSMehdi Amini std::string moduleStr = R"mlir( 28263237cddSRiver Riddle func.func private @callback(%arg0: memref<?x?xf32>, %coefficient: i32) attributes { llvm.emit_c_interface } 28363237cddSRiver Riddle func.func @caller_for_callback(%arg0: memref<?x?xf32>, %coefficient: i32) attributes { llvm.emit_c_interface } { 284e2310704SJulian Gross %unranked = memref.cast %arg0: memref<?x?xf32> to memref<*xf32> 2859680ea5cSMehdi Amini call @callback(%arg0, %coefficient) : (memref<?x?xf32>, i32) -> () 2869680ea5cSMehdi Amini return 2879680ea5cSMehdi Amini } 2889680ea5cSMehdi Amini )mlir"; 289*0d9dc421SJonas Paulsson #endif 290*0d9dc421SJonas Paulsson 291b77bac05SAlex Zinenko DialectRegistry registry; 292b77bac05SAlex Zinenko registerAllDialects(registry); 2930e9523efSSergio Afonso registerBuiltinDialectTranslation(registry); 294b77bac05SAlex Zinenko registerLLVMDialectTranslation(registry); 295b77bac05SAlex Zinenko MLIRContext context(registry); 296dfaadf6bSChristian Sigg auto module = parseSourceString<ModuleOp>(moduleStr, &context); 2979680ea5cSMehdi Amini ASSERT_TRUE(!!module); 2989680ea5cSMehdi Amini ASSERT_TRUE(succeeded(lowerToLLVMDialect(*module))); 2999680ea5cSMehdi Amini auto jitOrError = ExecutionEngine::create(*module); 3009680ea5cSMehdi Amini ASSERT_TRUE(!!jitOrError); 3019680ea5cSMehdi Amini auto jit = std::move(jitOrError.get()); 3029680ea5cSMehdi Amini // Define any extra symbols so they're available at runtime. 3039680ea5cSMehdi Amini jit->registerSymbols([&](llvm::orc::MangleAndInterner interner) { 3049680ea5cSMehdi Amini llvm::orc::SymbolMap symbolMap; 30552556c8eSNicolas Vasilache symbolMap[interner("_mlir_ciface_callback")] = { 30652556c8eSNicolas Vasilache llvm::orc::ExecutorAddr::fromPtr(memrefMultiply), 307151b58d8SLang Hames llvm::JITSymbolFlags::Exported}; 3089680ea5cSMehdi Amini return symbolMap; 3099680ea5cSMehdi Amini }); 3109680ea5cSMehdi Amini 3119680ea5cSMehdi Amini int32_t coefficient = 3.; 31202b6fb21SMehdi Amini llvm::Error error = jit->invoke("caller_for_callback", &*a, coefficient); 3139680ea5cSMehdi Amini ASSERT_TRUE(!error); 3149680ea5cSMehdi Amini count = 1; 31502b6fb21SMehdi Amini for (float elt : *a) 3169680ea5cSMehdi Amini ASSERT_EQ(elt, coefficient * count++); 3179680ea5cSMehdi Amini } 3189680ea5cSMehdi Amini 319d6efb6fcSMehdi Amini #endif // _WIN32 320