1//===- executionengine_test.go - Tests for executionengine ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file tests bindings for the executionengine component.
10//
11//===----------------------------------------------------------------------===//
12
13package llvm
14
15import (
16	"testing"
17)
18
19func TestFactorial(t *testing.T) {
20	LinkInMCJIT()
21	InitializeNativeTarget()
22	InitializeNativeAsmPrinter()
23
24	mod := NewModule("fac_module")
25
26	fac_args := []Type{Int32Type()}
27	fac_type := FunctionType(Int32Type(), fac_args, false)
28	fac := AddFunction(mod, "fac", fac_type)
29	fac.SetFunctionCallConv(CCallConv)
30	n := fac.Param(0)
31
32	entry := AddBasicBlock(fac, "entry")
33	iftrue := AddBasicBlock(fac, "iftrue")
34	iffalse := AddBasicBlock(fac, "iffalse")
35	end := AddBasicBlock(fac, "end")
36
37	builder := NewBuilder()
38	defer builder.Dispose()
39
40	builder.SetInsertPointAtEnd(entry)
41	If := builder.CreateICmp(IntEQ, n, ConstInt(Int32Type(), 0, false), "cmptmp")
42	builder.CreateCondBr(If, iftrue, iffalse)
43
44	builder.SetInsertPointAtEnd(iftrue)
45	res_iftrue := ConstInt(Int32Type(), 1, false)
46	builder.CreateBr(end)
47
48	builder.SetInsertPointAtEnd(iffalse)
49	n_minus := builder.CreateSub(n, ConstInt(Int32Type(), 1, false), "subtmp")
50	call_fac_args := []Value{n_minus}
51	call_fac := builder.CreateCall(fac, call_fac_args, "calltmp")
52	res_iffalse := builder.CreateMul(n, call_fac, "multmp")
53	builder.CreateBr(end)
54
55	builder.SetInsertPointAtEnd(end)
56	res := builder.CreatePHI(Int32Type(), "result")
57	phi_vals := []Value{res_iftrue, res_iffalse}
58	phi_blocks := []BasicBlock{iftrue, iffalse}
59	res.AddIncoming(phi_vals, phi_blocks)
60	builder.CreateRet(res)
61
62	err := VerifyModule(mod, ReturnStatusAction)
63	if err != nil {
64		t.Errorf("Error verifying module: %s", err)
65		return
66	}
67
68	options := NewMCJITCompilerOptions()
69	options.SetMCJITOptimizationLevel(2)
70	options.SetMCJITEnableFastISel(true)
71	options.SetMCJITNoFramePointerElim(true)
72	options.SetMCJITCodeModel(CodeModelJITDefault)
73	engine, err := NewMCJITCompiler(mod, options)
74	if err != nil {
75		t.Errorf("Error creating JIT: %s", err)
76		return
77	}
78	defer engine.Dispose()
79
80	pass := NewPassManager()
81	defer pass.Dispose()
82
83	pass.AddConstantPropagationPass()
84	pass.AddInstructionCombiningPass()
85	pass.AddPromoteMemoryToRegisterPass()
86	pass.AddGVNPass()
87	pass.AddCFGSimplificationPass()
88	pass.Run(mod)
89
90	exec_args := []GenericValue{NewGenericValueFromInt(Int32Type(), 10, false)}
91	exec_res := engine.RunFunction(fac, exec_args)
92	var fac10 uint64 = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1
93	if exec_res.Int(false) != fac10 {
94		t.Errorf("Expected %d, got %d", fac10, exec_res.Int(false))
95	}
96}
97