├── .gitmodules ├── arch ├── trampoline.go ├── trampoline_asm.s └── trampoline_test.go ├── cpp ├── llvm_bridge.h ├── helpers.h ├── llvm_bridge_test.cpp ├── CMakeLists.txt ├── helpers.cpp ├── helpers_test.cpp ├── TiJIT_test.cpp ├── llvm_bridge.cpp └── TiJIT.h ├── tools ├── Makefile ├── tools.go └── go.mod ├── ast ├── node.go ├── type_utils.go ├── constant.go ├── bin_ops.go ├── col.go ├── decimal_ops.go └── decimal_opt_test.go ├── gen ├── aot │ ├── decimal_aot_test.go │ ├── decimal_aot.go │ ├── main │ │ └── helper.go │ └── decimal_opt.ll ├── column_writer.go ├── chunk_reader_test.go ├── column_writer_test.go ├── code_gen_context_test.go ├── chunk_reader.go └── code_gen_context.go ├── .gitignore ├── program ├── abi_test.go ├── abi.go ├── machine_code_test.go └── machine_code.go ├── .golangci.yml ├── Makefile ├── compile ├── trampoline.go ├── trampoline_test.go ├── llvm_bridge.go └── llvm_bridge_test.go ├── go.mod ├── README.md └── LICENSE /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tidb"] 2 | path = tidb 3 | url = git@github.com:liuzix/tidb.git 4 | -------------------------------------------------------------------------------- /arch/trampoline.go: -------------------------------------------------------------------------------- 1 | package arch 2 | 3 | func CallWithArg(funcPtr, arg uintptr) uintptr 4 | -------------------------------------------------------------------------------- /cpp/llvm_bridge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern "C" void* compileLLVMIR(const char* ir, size_t len); 5 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | all: gofumports golangci-lint 2 | 3 | gofumports: 4 | go build -o bin/$@ mvdan.cc/gofumpt/gofumports 5 | 6 | golangci-lint: 7 | go build -o bin/$@ github.com/golangci/golangci-lint/cmd/golangci-lint -------------------------------------------------------------------------------- /ast/node.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen" 5 | irTypes "github.com/llir/llvm/ir/types" 6 | "github.com/llir/llvm/ir/value" 7 | ) 8 | 9 | type Node interface { 10 | Compile(ctx gen.CodeGenContext) value.Value 11 | GetIRType() (irTypes.Type, error) 12 | } 13 | -------------------------------------------------------------------------------- /arch/trampoline_asm.s: -------------------------------------------------------------------------------- 1 | // +build go1.17,!go1.18 2 | 3 | 4 | #include "go_asm.h" 5 | #include "funcdata.h" 6 | #include "textflag.h" 7 | 8 | // func CallWithArg(funcPtr, arg) uintptr 9 | TEXT ·CallWithArg(SB), NOSPLIT, $0-4096 10 | 11 | MOVQ first_arg+0(FP), AX 12 | MOVQ second_arg+8(FP), DI 13 | CALL AX 14 | MOVQ AX, ret+0x10(FP) 15 | RET 16 | -------------------------------------------------------------------------------- /ast/type_utils.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen/aot" 5 | irTypes "github.com/llir/llvm/ir/types" 6 | "github.com/pingcap/tidb/types" 7 | ) 8 | 9 | func IRTypeFromEvalType(tp types.EvalType) irTypes.Type { 10 | switch tp { 11 | case types.ETInt: 12 | return irTypes.I64 13 | case types.ETDecimal: 14 | return irTypes.NewPointer(aot.DecimalType) 15 | default: 16 | return nil 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /gen/aot/decimal_aot_test.go: -------------------------------------------------------------------------------- 1 | package aot 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestDecimalAotModuleLoaded(t *testing.T) { 10 | require.NotNil(t, DecimalModule) 11 | } 12 | 13 | func TestDecimalMulFunctionFound(t *testing.T) { 14 | require.Equal(t, decimalMulFuncName, DecimalMulFunction.Name()) 15 | require.Equal(t, decimalSubFuncName, DecimalSubFunction.Name()) 16 | } 17 | -------------------------------------------------------------------------------- /ast/constant.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen" 5 | irTypes "github.com/llir/llvm/ir/types" 6 | "github.com/llir/llvm/ir/value" 7 | "github.com/pingcap/tidb/types" 8 | ) 9 | 10 | type Constant struct { 11 | evalTp types.EvalType 12 | integer int 13 | decimal types.MyDecimal 14 | } 15 | 16 | func (c Constant) Compile(ctx gen.CodeGenContext) value.Value { 17 | panic("implement me") 18 | } 19 | 20 | func (c Constant) GetIRType() (irTypes.Type, error) { 21 | panic("implement me") 22 | } 23 | -------------------------------------------------------------------------------- /cpp/helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace llvm; 10 | 11 | struct GlobalInitializer; 12 | 13 | std::unique_ptr makeMemoryBuffer(const char* bytes, size_t len); 14 | const Target* getLLVMTarget(); 15 | std::unique_ptr makeModuleFromMemoryBuffer(llvm::LLVMContext& context, MemoryBufferRef buf); 16 | std::string generateFreshJITSymbolName(); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | tools/bin 17 | .idea 18 | cpp/Makefile 19 | cpp/cmake-build-debug 20 | cpp/cmake-build-debug-coverage 21 | cpp/Testing 22 | cpp/cmake_install.cmake 23 | cpp/CMakeCache.txt 24 | cpp/CTestTestfile.cmake 25 | llvm_bridge_test 26 | libllvm_bridge.a 27 | *.cbp 28 | CMakeFiles -------------------------------------------------------------------------------- /cpp/llvm_bridge_test.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm_bridge.h" 2 | 3 | #include 4 | 5 | TEST(TestLLVMBridge, TestCompileLLVMIR) 6 | { 7 | std::string ir = R"( 8 | define i64 @jit_main(i64 %x) { 9 | %tmp = add i64 1, %x 10 | ret i64 %tmp 11 | } 12 | )"; 13 | const char* buf = ir.data(); 14 | size_t len = ir.size(); 15 | 16 | void* result = compileLLVMIR(buf, len); 17 | EXPECT_NE(result, nullptr); 18 | 19 | auto fp = (uint64_t(*)(uint64_t))(result); 20 | 21 | for (int i = 0; i < 1000; i++) { 22 | uint64_t ret = fp(i); 23 | EXPECT_EQ(ret, i + 1); 24 | } 25 | } -------------------------------------------------------------------------------- /program/abi_test.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | // read only 10 | var addFunctionSystemABI = []byte{ 11 | 0x48, 0x83, 0xC7, 0x01, // add rdi,0x1 12 | 0x48, 0x89, 0xF8, // mov rax,rdi 13 | 0xC3, // ret 14 | } 15 | 16 | func TestAMD64ConvertToGoABI(t *testing.T) { 17 | code := NewMachineCode(addFunctionSystemABI) 18 | defer func() { 19 | err := code.Release() 20 | require.NoError(t, err) 21 | }() 22 | 23 | abi := NewAMD64PlatformABI() 24 | err := abi.ConvertToGoABI(code) 25 | require.NoError(t, err) 26 | 27 | result, err := code.Execute(10, 0) 28 | require.NoError(t, err) 29 | require.Equal(t, Result(11), result) 30 | } 31 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - unconvert 4 | - unparam 5 | - revive 6 | 7 | linters-settings: 8 | revive: 9 | ignore-generated-header: false 10 | severity: error 11 | confidence: 0.8 12 | error-code: -1 13 | warning-code: -1 14 | rules: 15 | - name: blank-imports 16 | - name: context-as-argument 17 | - name: dot-imports 18 | - name: error-return 19 | - name: error-strings 20 | - name: error-naming 21 | - name: exported 22 | - name: if-return 23 | - name: var-naming 24 | - name: package-comments 25 | - name: range 26 | - name: receiver-naming 27 | - name: indent-error-flow 28 | - name: superfluous-else 29 | - name: modifies-parameter 30 | - name: unreachable-code -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PARALLEL=4 2 | GOTEST := CGO_ENABLED=1 go test -p $(PARALLEL) --race 3 | FAIL_ON_STDOUT := awk '{ print } END { if (NR > 0) { exit 1 } }' 4 | 5 | PACKAGE_LIST := go list ./... 6 | PACKAGES := $$($(PACKAGE_LIST)) 7 | GOFILES := $$(find . -name '*.go' -type f | grep -vE 'tidb/') 8 | 9 | unit_test: 10 | $(GOTEST) $(PACKAGES) 11 | 12 | build_unit_test: 13 | $(GOTEST) $(PACKAGES) -c 14 | 15 | tools_setup: 16 | @echo "setup build and check tools" 17 | @cd tools && make 18 | 19 | fmt: 20 | @echo "gofmt (simplify)" 21 | tools/bin/gofumports -l -w $(GOFILES) 2>&1 | $(FAIL_ON_STDOUT) 22 | 23 | lint: 24 | echo "golangci-lint"; \ 25 | tools/bin/golangci-lint run --config=./.golangci.yml --timeout 10m0s 26 | 27 | tidy: 28 | @echo "check go mod tidy" 29 | go mod tidy 30 | 31 | check: tools_setup lint fmt tidy -------------------------------------------------------------------------------- /program/abi.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | type PlatformABI interface { 4 | // ConvertToGoABI converts the native calling convention to 5 | // Go calling convention. The MachineCode object is modified. 6 | ConvertToGoABI(code *MachineCode) error 7 | } 8 | 9 | type AMD64PlatformABI struct{} 10 | 11 | func NewAMD64PlatformABI() PlatformABI { 12 | return &AMD64PlatformABI{} 13 | } 14 | 15 | var amd64Prolog = []byte{ 16 | 0x48, 0x89, 0xC7, // mov rdi,rax 17 | } 18 | 19 | func (p *AMD64PlatformABI) ConvertToGoABI(code *MachineCode) error { 20 | if err := code.Release(); err != nil { 21 | return err 22 | } 23 | 24 | newCodeLen := len(amd64Prolog) + len(code.Code) 25 | newCode := make([]byte, 0, newCodeLen) 26 | newCode = append(newCode, amd64Prolog...) 27 | newCode = append(newCode, code.Code...) 28 | 29 | code.Code = newCode 30 | return nil 31 | } 32 | -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | //go:build tools 15 | // +build tools 16 | 17 | // Tool dependencies are tracked here to make go module happy 18 | // Refer https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 19 | 20 | package tools 21 | 22 | import ( 23 | _ "github.com/golangci/golangci-lint/pkg/commands" 24 | _ "mvdan.cc/gofumpt/gofumports" 25 | ) 26 | -------------------------------------------------------------------------------- /compile/trampoline.go: -------------------------------------------------------------------------------- 1 | package compile 2 | 3 | /* 4 | #include 5 | 6 | uint64_t CallCGOTrampoline(uint64_t ptr, uint64_t arg) { 7 | uint64_t (*fn)(uint64_t) = (uint64_t (*)(uint64_t))ptr; 8 | return fn(arg); 9 | } 10 | */ 11 | import "C" 12 | 13 | import ( 14 | "runtime" 15 | 16 | "github.com/liuzix/ticompile/program" 17 | ) 18 | 19 | var trampoline = buildTrampoline() 20 | 21 | func CallCGOTrampoline(ptr, arg uintptr) uintptr{ 22 | return uintptr(C.CallCGOTrampoline(C.ulong(ptr), C.ulong(arg))) 23 | } 24 | 25 | //go:nosplit 26 | func CallTrampoline(ptr, arg program.Arg) (program.Result, error) { 27 | runtime.LockOSThread() 28 | ret, err := trampoline.Execute(ptr, arg) 29 | runtime.UnlockOSThread() 30 | if err != nil { 31 | return 0, err 32 | } 33 | return ret, nil 34 | } 35 | 36 | func buildTrampoline() *program.MachineCode { 37 | asm := []byte{ 38 | 0x48, 0x89, 0xDF, // mov rdi, rbx 39 | 0xFF, 0xD0, // call rax 40 | 0xC3, // ret 41 | } 42 | return program.NewMachineCode(asm) 43 | } 44 | -------------------------------------------------------------------------------- /compile/trampoline_test.go: -------------------------------------------------------------------------------- 1 | package compile 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/liuzix/ticompile/program" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | // read only 11 | var incFunction = []byte{ 12 | // Note that this is the native calling convention 13 | 0x48, 0x83, 0xC7, 0x01, // add rdi, 0x1 14 | 0x48, 0x89, 0xF8, // mov rax, rdi 15 | 0xC3, // ret 16 | } 17 | 18 | func TestCallTrampoline(t *testing.T) { 19 | targetFunc := program.NewMachineCode(incFunction) 20 | rawPtr, err := targetFunc.RawFuncPtr() 21 | require.NoError(t, err) 22 | 23 | result := CallCGOTrampoline(rawPtr, 2) 24 | require.Equal(t, uintptr(3), result) 25 | } 26 | 27 | func BenchmarkCallTrampoline(b *testing.B) { 28 | targetFunc := program.NewMachineCode(incFunction) 29 | rawPtr, err := targetFunc.RawFuncPtr() 30 | if err != nil { 31 | b.FailNow() 32 | } 33 | b.ResetTimer() 34 | 35 | for i := 0; i < b.N; i++ { 36 | result := CallCGOTrampoline(rawPtr, 2) 37 | if result != 3 { 38 | b.FailNow() 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /arch/trampoline_test.go: -------------------------------------------------------------------------------- 1 | package arch 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/liuzix/ticompile/program" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | // read only 11 | var incFunction = []byte{ 12 | // Note that this is the native calling convention 13 | 0x48, 0x83, 0xC7, 0x01, // add rdi, 0x1 14 | 0x48, 0x89, 0xF8, // mov rax, rdi 15 | 0xC3, // ret 16 | } 17 | 18 | func TestCallTrampoline(t *testing.T) { 19 | targetFunc := program.NewMachineCode(incFunction) 20 | rawPtr, err := targetFunc.RawFuncPtr() 21 | require.NoError(t, err) 22 | 23 | result := CallWithArg(rawPtr, 2) 24 | require.NoError(t, err) 25 | require.Equal(t, uintptr(3), result) 26 | } 27 | 28 | func BenchmarkCallTrampoline(b *testing.B) { 29 | targetFunc := program.NewMachineCode(incFunction) 30 | rawPtr, err := targetFunc.RawFuncPtr() 31 | if err != nil { 32 | b.FailNow() 33 | } 34 | b.ResetTimer() 35 | 36 | for i := 0; i < b.N; i++ { 37 | result := CallWithArg(rawPtr, 2) 38 | if result != 3 { 39 | b.FailNow() 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /compile/llvm_bridge.go: -------------------------------------------------------------------------------- 1 | package compile 2 | 3 | /* 4 | #include 5 | #include 6 | #cgo LDFLAGS: -L${SRCDIR}/../cpp -lllvm_bridge -Wl,-rpath=${SRCDIR}/../cpp 7 | void* compileLLVMIR(const char* ir, size_t len); 8 | */ 9 | import "C" 10 | 11 | import ( 12 | "unsafe" 13 | 14 | "github.com/liuzix/ticompile/program" 15 | "github.com/pingcap/log" 16 | "go.uber.org/zap" 17 | ) 18 | 19 | type CompiledFunction = func(arg program.Arg) (program.Result, error) 20 | 21 | func LLVMCompileIR(bitcode []byte) CompiledFunction { 22 | buf := C.CString(string(bitcode)) 23 | defer C.free(unsafe.Pointer(buf)) 24 | 25 | rawFuncPtr := uintptr(C.compileLLVMIR(buf, C.size_t(len(bitcode)))) 26 | if rawFuncPtr == 0 { 27 | log.Panic("compileLLVMIR failed", 28 | zap.Binary("bitcode", bitcode)) 29 | } 30 | log.Debug("LLVM JIT returned function ptr", zap.Uintptr("ptr", rawFuncPtr)) 31 | 32 | return func(arg program.Arg) (program.Result, error) { 33 | result := CallCGOTrampoline(rawFuncPtr, arg) 34 | return result, nil 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /compile/llvm_bridge_test.go: -------------------------------------------------------------------------------- 1 | package compile 2 | 3 | import ( 4 | "github.com/pingcap/tidb/br/pkg/lightning/log" 5 | "go.uber.org/zap/zapcore" 6 | "testing" 7 | 8 | "github.com/liuzix/ticompile/program" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestCompileIR(t *testing.T) { 13 | str := ` 14 | define i64 @jit_main(i64 %x) { 15 | %tmp = add i64 1, %x 16 | ret i64 %tmp 17 | }` 18 | fn := LLVMCompileIR([]byte(str)) 19 | require.NotNil(t, fn) 20 | 21 | for i := 0; i < 10000; i++ { 22 | res, err := fn(program.Arg(i)) 23 | require.NoError(t, err) 24 | require.Equal(t, program.Result(i+1), res) 25 | } 26 | } 27 | 28 | func BenchmarkCompileIR(b *testing.B) { 29 | str := ` 30 | define i64 @jit_main(i64 %x) { 31 | %tmp = add i64 1, %x 32 | ret i64 %tmp 33 | }` 34 | log.SetLevel(zapcore.WarnLevel) 35 | defer log.SetLevel(zapcore.InfoLevel) 36 | b.ResetTimer() 37 | 38 | for i := 0; i < b.N; i++ { 39 | fn := LLVMCompileIR([]byte(str)) 40 | if fn == nil { 41 | b.FailNow() 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(llvm_bridge) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | 6 | find_package(LLVM REQUIRED CONFIG) 7 | 8 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 9 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 10 | 11 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 12 | include_directories(${LLVM_INCLUDE_DIRS}) 13 | separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS}) 14 | add_definitions(${LLVM_DEFINITIONS_LIST}) 15 | llvm_map_components_to_libnames(llvm_libs support core irreader target X86 orcjit) 16 | 17 | message(STATUS "Linking LLVM libraries ${llvm_libs}") 18 | 19 | find_package(spdlog REQUIRED) 20 | 21 | enable_testing() 22 | find_package(GTest REQUIRED) 23 | include_directories(${GTEST_INCLUDE_DIR}) 24 | 25 | add_library(llvm_bridge SHARED llvm_bridge.cpp helpers.cpp helpers.h TiJIT.h) 26 | target_link_libraries(llvm_bridge PUBLIC ${llvm_libs} spdlog::spdlog) 27 | 28 | add_executable(llvm_bridge_test helpers_test.cpp TiJIT_test.cpp llvm_bridge_test.cpp) 29 | target_link_libraries(llvm_bridge_test gtest_main gtest llvm_bridge) -------------------------------------------------------------------------------- /program/machine_code_test.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | // read only 10 | var incFunction = []byte{ 11 | 0x48, 0x83, 0xC0, 0x01, // add rax,0x1 12 | 0xC3, // ret 13 | } 14 | 15 | func TestMachineCodeIncFunc(t *testing.T) { 16 | code := NewMachineCode(incFunction) 17 | defer func() { 18 | err := code.Release() 19 | require.NoError(t, err) 20 | }() 21 | 22 | for i := 0; i < 5; i++ { 23 | // Run multiple times 24 | result, err := code.Execute(5, 0) 25 | require.NoError(t, err) 26 | require.Equal(t, Result(6), result) 27 | } 28 | } 29 | 30 | // read only 31 | var addFunction = []byte{ 32 | 0x48, 0x01, 0xD8, // add rax, rbx 33 | 0xC3, // ret 34 | } 35 | 36 | func TestMachineCodeAddFunc(t *testing.T) { 37 | code := NewMachineCode(addFunction) 38 | defer func() { 39 | err := code.Release() 40 | require.NoError(t, err) 41 | }() 42 | 43 | for i := 0; i < 5; i++ { 44 | // Run multiple times 45 | result, err := code.Execute(5, 6) 46 | require.NoError(t, err) 47 | require.Equal(t, Result(11), result) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ast/bin_ops.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen" 5 | irTypes "github.com/llir/llvm/ir/types" 6 | "github.com/llir/llvm/ir/value" 7 | "github.com/pingcap/errors" 8 | "github.com/pingcap/tidb/parser/opcode" 9 | ) 10 | 11 | type BinOp struct { 12 | Left Node 13 | Right Node 14 | Op opcode.Op 15 | } 16 | 17 | func (o *BinOp) Compile(ctx gen.CodeGenContext) value.Value { 18 | lVal := o.Left.Compile(ctx) 19 | rVal := o.Right.Compile(ctx) 20 | 21 | switch o.Op { 22 | case opcode.Plus: 23 | return ctx.Block().NewAdd(lVal, rVal) 24 | case opcode.Mul: 25 | return ctx.Block().NewMul(lVal, rVal) 26 | default: 27 | panic("implement me") 28 | } 29 | } 30 | 31 | func (o *BinOp) GetIRType() (irTypes.Type, error) { 32 | lType, err := o.Left.GetIRType() 33 | if err != nil { 34 | return nil, errors.Trace(err) 35 | } 36 | 37 | rType, err := o.Right.GetIRType() 38 | if err != nil { 39 | return nil, errors.Trace(err) 40 | } 41 | 42 | if lType.Equal(rType) { 43 | return lType, nil 44 | } 45 | 46 | return nil, errors.Trace(errors.Errorf("BinOp: types of operands not compatible: %s and %s", 47 | lType.Name(), rType.Name())) 48 | } 49 | -------------------------------------------------------------------------------- /cpp/helpers.cpp: -------------------------------------------------------------------------------- 1 | #include "helpers.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace llvm; 14 | 15 | std::unique_ptr makeMemoryBuffer(const char* bytes, size_t len) 16 | { 17 | StringRef stringRef(bytes, len); 18 | return MemoryBuffer::getMemBuffer(stringRef, "", 19 | false /* no null-terminator */); 20 | } 21 | 22 | std::unique_ptr makeModuleFromMemoryBuffer(llvm::LLVMContext& context, MemoryBufferRef buf) 23 | { 24 | llvm::SMDiagnostic err; 25 | auto module = llvm::parseIR(buf, err, context); 26 | if (!module) { 27 | spdlog::error("failed to parse IR: {}", 28 | err.getMessage()); 29 | return nullptr; 30 | } 31 | return module; 32 | } 33 | 34 | std::string generateFreshJITSymbolName() 35 | { 36 | static std::atomic_int64_t counter(0); 37 | int64_t freshCount = counter.fetch_add(1, std::memory_order_seq_cst); 38 | return std::to_string(freshCount); 39 | } -------------------------------------------------------------------------------- /gen/column_writer.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen/aot" 5 | "github.com/llir/llvm/ir/constant" 6 | irTypes "github.com/llir/llvm/ir/types" 7 | "github.com/llir/llvm/ir/value" 8 | ) 9 | 10 | type ColumnWriter struct { 11 | columnPointer value.Value 12 | } 13 | 14 | // NewColumnWriter returns a new ColumnWriter. 15 | // TODO be compatible with variable sized columns. 16 | func NewColumnWriter(ctx CodeGenContext) *ColumnWriter { 17 | idxConst := constant.NewInt(irTypes.I64, 1) 18 | colPtrPtr := ctx.Block().NewGetElementPtr(columnPointerType, ctx.Param(), idxConst) 19 | colPtr := ctx.Block().NewLoad(columnPointerType, colPtrPtr) 20 | 21 | return &ColumnWriter{ 22 | columnPointer: colPtr, 23 | } 24 | } 25 | 26 | func (w *ColumnWriter) PutInt64(ctx CodeGenContext, rowIdx value.Value, val value.Value) { 27 | addr := ctx.Block().NewGetElementPtr(irTypes.I64, w.columnPointer, rowIdx) 28 | ctx.Block().NewStore(val, addr) 29 | } 30 | 31 | func (w *ColumnWriter) PutDecimal(ctx CodeGenContext, rowIdx value.Value, val value.Value) { 32 | ptr := ctx.Block().NewBitCast(w.columnPointer, irTypes.NewPointer(aot.DecimalType)) 33 | addr := ctx.Block().NewGetElementPtr(aot.DecimalType, ptr, rowIdx) 34 | decVal := ctx.Block().NewLoad(aot.DecimalType, val) 35 | ctx.Block().NewStore(decVal, addr) 36 | } 37 | -------------------------------------------------------------------------------- /cpp/helpers_test.cpp: -------------------------------------------------------------------------------- 1 | #include "helpers.h" 2 | 3 | #include 4 | 5 | TEST(HelperTest, TestMakeMemoryBuffer) 6 | { 7 | const char testData[] = { 0x1, 0x2, 0x3, 0x4 }; 8 | size_t testDataLen = 4; 9 | auto memoryBuf = makeMemoryBuffer(testData, testDataLen); 10 | 11 | EXPECT_EQ(memoryBuf->getBufferSize(), testDataLen); 12 | EXPECT_EQ(memoryBuf->getBufferStart()[0], 0x1); 13 | EXPECT_EQ(memoryBuf->getBufferStart()[1], 0x2); 14 | EXPECT_EQ(memoryBuf->getBufferStart()[2], 0x3); 15 | EXPECT_EQ(memoryBuf->getBufferStart()[3], 0x4); 16 | } 17 | 18 | TEST(HelperTest, TestMakeModuleFromMemoryBuffer) 19 | { 20 | std::string ir = R"( 21 | define i32 @mul_add(i32 %x, i32 %y, i32 %z) { 22 | entry: 23 | %tmp = mul i32 %x, %y 24 | %tmp2 = add i32 %tmp, %z 25 | ret i32 %tmp2 26 | } 27 | )"; 28 | auto buf = makeMemoryBuffer(ir.data(), ir.size()); 29 | 30 | llvm::LLVMContext context; 31 | auto module = makeModuleFromMemoryBuffer(context, buf->getMemBufferRef()); 32 | EXPECT_TRUE(!!module); 33 | } 34 | 35 | TEST(HelperTest, TestGenerateFreshJITSymbolName) 36 | { 37 | std::string oldName; 38 | for (int i = 0; i < 100; i++) { 39 | std::string newName = generateFreshJITSymbolName(); 40 | EXPECT_NE(newName, oldName); 41 | oldName = std::move(newName); 42 | } 43 | } -------------------------------------------------------------------------------- /cpp/TiJIT_test.cpp: -------------------------------------------------------------------------------- 1 | #include "TiJIT.h" 2 | 3 | #include "helpers.h" 4 | #include 5 | #include 6 | 7 | TEST(TestTiJIT, TestTiJITBasics) 8 | { 9 | llvm::InitializeNativeTarget(); 10 | llvm::InitializeNativeTargetAsmPrinter(); 11 | llvm::InitializeNativeTargetAsmParser(); 12 | auto jit = cantFail(TiJIT::Create()); 13 | EXPECT_TRUE(!!jit); 14 | 15 | std::string ir = R"( 16 | define i64 @jit_main(i64 %x) { 17 | %tmp = add i64 1, %x 18 | ret i64 %tmp 19 | } 20 | )"; 21 | auto buf = makeMemoryBuffer(ir.data(), ir.size()); 22 | 23 | llvm::LLVMContext context; 24 | auto module = makeModuleFromMemoryBuffer(context, buf->getMemBufferRef()); 25 | EXPECT_TRUE(!!module); 26 | 27 | auto layout = jit->getDataLayout(); 28 | module->setDataLayout(layout); 29 | auto jitMain = module->getFunction("jit_main"); 30 | 31 | const std::string freshName = generateFreshJITSymbolName(); 32 | jitMain->setName(freshName); 33 | jit->addModule(std::move(module)); 34 | 35 | auto sym = cantFail(jit->lookup(freshName)); 36 | auto* fp = (int64_t(*)(int64_t))(intptr_t)sym.getAddress(); 37 | 38 | EXPECT_EQ(fp(2), 3); 39 | 40 | EXPECT_TRUE(jit->removeModule(freshName)); 41 | 42 | auto result = jit->lookup(freshName); 43 | // Asserts failure 44 | EXPECT_TRUE(!result); 45 | } -------------------------------------------------------------------------------- /gen/chunk_reader_test.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "testing" 5 | "unsafe" 6 | 7 | "github.com/liuzix/ticompile/compile" 8 | "github.com/llir/llvm/ir/constant" 9 | irTypes "github.com/llir/llvm/ir/types" 10 | "github.com/pingcap/log" 11 | "github.com/pingcap/tidb/parser/mysql" 12 | "github.com/pingcap/tidb/types" 13 | "github.com/pingcap/tidb/util/chunk" 14 | "github.com/stretchr/testify/require" 15 | "go.uber.org/zap" 16 | ) 17 | 18 | func TestReadInt64FromChunk(t *testing.T) { 19 | chunkTypes := []*types.FieldType{types.NewFieldType(mysql.TypeLonglong)} 20 | inputChunk := chunk.New(chunkTypes, 1024, 1024) 21 | for i := 0; i < 100; i++ { 22 | inputChunk.AppendInt64(0, int64(i)) 23 | } 24 | 25 | codeGenCtx := NewCodeGenContext("") 26 | chunkReader := NewChunkReader() 27 | 28 | val := chunkReader.ReadInt64(codeGenCtx, 0, constant.NewInt(irTypes.I64, 50)) 29 | codeGenCtx.Block().NewRet(val) 30 | 31 | asmText := codeGenCtx.Module().String() 32 | log.Info("compiled IR", zap.String("asm", asmText)) 33 | 34 | fn := compile.LLVMCompileIR([]byte(asmText)) 35 | 36 | inputVec := []uintptr{ 37 | 0, 38 | 0, 39 | uintptr(unsafe.Pointer(&inputChunk.Column(0).Int64s()[0])), 40 | } 41 | inputParam := uintptr(unsafe.Pointer(&inputVec[0])) 42 | log.Info("input", zap.Uintptr("ptr", inputParam)) 43 | res, err := fn(inputParam) 44 | require.NoError(t, err) 45 | require.Equal(t, uintptr(50), res) 46 | } 47 | -------------------------------------------------------------------------------- /gen/column_writer_test.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "testing" 5 | "unsafe" 6 | 7 | "github.com/liuzix/ticompile/compile" 8 | "github.com/llir/llvm/ir/constant" 9 | irTypes "github.com/llir/llvm/ir/types" 10 | "github.com/pingcap/log" 11 | "github.com/pingcap/tidb/parser/mysql" 12 | tidbTypes "github.com/pingcap/tidb/types" 13 | "github.com/pingcap/tidb/util/chunk" 14 | "github.com/stretchr/testify/require" 15 | "go.uber.org/zap" 16 | ) 17 | 18 | func newColumnForTest(fieldType *tidbTypes.FieldType, capacity int) *chunk.Column { 19 | return chunk.NewColumn(fieldType, capacity) 20 | } 21 | 22 | func TestColumnWriterPutInt64(t *testing.T) { 23 | elemType := tidbTypes.NewFieldType(mysql.TypeLonglong) 24 | 25 | col := newColumnForTest(elemType, 1024) 26 | require.Equal(t, 0, len(col.Int64s())) 27 | 28 | ctx := NewCodeGenContext("") 29 | writer := NewColumnWriter(ctx) 30 | for i := 0; i < 1024; i++ { 31 | writer.PutInt64(ctx, 32 | constant.NewInt(irTypes.I64, int64(i)), 33 | constant.NewInt(irTypes.I64, int64(i+1))) 34 | } 35 | ctx.Block().NewRet(constant.NewInt(irTypes.I64, 0)) // dummy return 36 | 37 | asm := ctx.Module().String() 38 | log.Info("generate IR", zap.String("asm", asm)) 39 | 40 | col.ResizeInt64(1024, true) 41 | inputVec := []uintptr{ 42 | 0, // limit 43 | uintptr(unsafe.Pointer(&col.Int64s()[0])), 44 | } 45 | inputParam := uintptr(unsafe.Pointer(&inputVec[0])) 46 | fn := compile.LLVMCompileIR([]byte(asm)) 47 | 48 | res, err := fn(inputParam) 49 | require.NoError(t, err) 50 | require.Equal(t, uintptr(0), res) 51 | 52 | for i := 0; i < 1024; i++ { 53 | val := col.GetInt64(i) 54 | require.Equal(t, int64(i+1), val) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ast/col.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen" 5 | irTypes "github.com/llir/llvm/ir/types" 6 | "github.com/llir/llvm/ir/value" 7 | "github.com/pingcap/log" 8 | "github.com/pingcap/tidb/types" 9 | "go.uber.org/zap" 10 | ) 11 | 12 | type ColNode struct { 13 | colIdx *int 14 | colIdxPlaceholder string 15 | tp irTypes.Type 16 | evalTp types.EvalType 17 | } 18 | 19 | func NewColNodeWithIdx(colIdx int, tp types.EvalType) *ColNode { 20 | return &ColNode{ 21 | colIdx: &colIdx, 22 | tp: IRTypeFromEvalType(tp), 23 | evalTp: tp, 24 | } 25 | } 26 | 27 | func NewColNodeWithPlaceholder(placeholder string, tp types.EvalType) *ColNode { 28 | return &ColNode{ 29 | colIdxPlaceholder: placeholder, 30 | tp: IRTypeFromEvalType(tp), 31 | evalTp: tp, 32 | } 33 | } 34 | 35 | func (c *ColNode) Compile(ctx gen.CodeGenContext) value.Value { 36 | var colIdx int 37 | if c.colIdx != nil { 38 | colIdx = *c.colIdx 39 | } else { 40 | colIdx = ctx.RelocateInputIdx(c.colIdxPlaceholder) 41 | } 42 | 43 | loopCtx, ok := ctx.(*gen.LoopCodeGenContext) 44 | if !ok { 45 | log.Panic("must be compiled within a loop", 46 | zap.Any("col-idx", c.colIdx), 47 | zap.String("col-idx-placeholder", c.colIdxPlaceholder), 48 | zap.Any("tp", c.tp)) 49 | } 50 | 51 | switch c.evalTp { 52 | case types.ETInt: 53 | return ctx.InputReader().ReadInt64(ctx, colIdx, loopCtx.LoopVar()) 54 | case types.ETDecimal: 55 | return ctx.InputReader().ReadDecimal(ctx, colIdx, loopCtx.LoopVar()) 56 | default: 57 | panic("implement me") 58 | } 59 | } 60 | 61 | func (c *ColNode) GetIRType() (irTypes.Type, error) { 62 | return c.tp, nil 63 | } 64 | -------------------------------------------------------------------------------- /gen/aot/decimal_aot.go: -------------------------------------------------------------------------------- 1 | package aot 2 | 3 | import ( 4 | _ "embed" 5 | 6 | "github.com/llir/llvm/asm" 7 | "github.com/llir/llvm/ir" 8 | irTypes "github.com/llir/llvm/ir/types" 9 | "github.com/pingcap/log" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | //go:embed decimal_opt.ll 14 | var decimalIRCode []byte 15 | 16 | var ( 17 | DecimalModule *ir.Module 18 | DecimalType irTypes.Type 19 | DecimalMulFunction *ir.Func 20 | DecimalSubFunction *ir.Func 21 | ) 22 | 23 | const ( 24 | decimalMulFuncName = "DecimalMul" 25 | decimalSubFuncName = "DecimalSub" 26 | decimalType = "MyDecimal" 27 | ) 28 | 29 | func init() { 30 | var err error 31 | DecimalModule, err = asm.ParseBytes("", decimalIRCode) 32 | if err != nil { 33 | log.Panic("failed to parse LLVM file decimal.ll", zap.Error(err)) 34 | } 35 | DecimalMulFunction = findDecimalMulFunction() 36 | DecimalSubFunction = findDecimalSubFunction() 37 | DecimalType = findDecimalType() 38 | 39 | } 40 | 41 | func findDecimalMulFunction() *ir.Func { 42 | for _, fn := range DecimalModule.Funcs { 43 | if fn.Name() == decimalMulFuncName { 44 | return fn 45 | } 46 | } 47 | log.Panic( 48 | "function not found", 49 | zap.String("func-name", decimalMulFuncName)) 50 | panic("unreachable") 51 | } 52 | 53 | func findDecimalSubFunction() *ir.Func { 54 | for _, fn := range DecimalModule.Funcs { 55 | if fn.Name() == decimalSubFuncName { 56 | return fn 57 | } 58 | } 59 | log.Panic( 60 | "function not found", 61 | zap.String("func-name", decimalSubFuncName)) 62 | panic("unreachable") 63 | } 64 | 65 | func findDecimalType() irTypes.Type { 66 | for _, tp := range DecimalModule.TypeDefs { 67 | if tp.Name() == decimalType { 68 | return tp 69 | } 70 | } 71 | log.Panic( 72 | "function not found", 73 | zap.String("func-name", decimalType)) 74 | panic("unreachable") 75 | } -------------------------------------------------------------------------------- /gen/code_gen_context_test.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/liuzix/ticompile/compile" 7 | "github.com/llir/llvm/ir/constant" 8 | irTypes "github.com/llir/llvm/ir/types" 9 | "github.com/pingcap/log" 10 | "github.com/stretchr/testify/require" 11 | "go.uber.org/zap" 12 | ) 13 | 14 | func TestGenLoop(t *testing.T) { 15 | ctx := NewCodeGenContext("") 16 | loc := ctx.Block().NewAlloca(irTypes.I64) 17 | ctx.Block().NewStore(constant.NewInt(irTypes.I64, 0), loc) 18 | limit := constant.NewInt(irTypes.I64, 101) 19 | 20 | loopCtx := ctx.Loop(limit) 21 | oldVal := loopCtx.Block().NewLoad(irTypes.I64, loc) 22 | newVal := loopCtx.Block().NewAdd(oldVal, loopCtx.LoopVar()) 23 | loopCtx.Block().NewStore(newVal, loc) 24 | loopCtx.FinishLoop() 25 | 26 | val := ctx.Block().NewLoad(irTypes.I64, loc) 27 | ctx.Block().NewRet(val) 28 | 29 | asm := ctx.Module().String() 30 | log.Info("TestGenLoop: generated IR", 31 | zap.String("ir", asm)) 32 | 33 | fn := compile.LLVMCompileIR([]byte(asm)) 34 | res, err := fn(0) 35 | require.NoError(t, err) 36 | require.Equal(t, uintptr(5050), res) 37 | } 38 | 39 | func BenchmarkLoop(b *testing.B) { 40 | ctx := NewCodeGenContext("") 41 | loc := ctx.Block().NewAlloca(irTypes.I64) 42 | ctx.Block().NewStore(constant.NewInt(irTypes.I64, 0), loc) 43 | limit := constant.NewInt(irTypes.I64, int64(b.N)) 44 | 45 | loopCtx := ctx.Loop(limit) 46 | oldVal := loopCtx.Block().NewLoad(irTypes.I64, loc) 47 | newVal := loopCtx.Block().NewAdd(oldVal, loopCtx.LoopVar()) 48 | loopCtx.Block().NewStore(newVal, loc) 49 | loopCtx.FinishLoop() 50 | 51 | val := ctx.Block().NewLoad(irTypes.I64, loc) 52 | ctx.Block().NewRet(val) 53 | 54 | asm := ctx.Module().String() 55 | log.Info("TestGenLoop: generated IR", 56 | zap.String("ir", asm)) 57 | 58 | fn := compile.LLVMCompileIR([]byte(asm)) 59 | 60 | b.ResetTimer() 61 | 62 | _, _ = fn(0) 63 | } -------------------------------------------------------------------------------- /gen/chunk_reader.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen/aot" 5 | "github.com/llir/llvm/ir/constant" 6 | irTypes "github.com/llir/llvm/ir/types" 7 | "github.com/llir/llvm/ir/value" 8 | ) 9 | 10 | type ChunkReader struct{} 11 | 12 | var columnPointerType = irTypes.NewPointer(irTypes.I64) 13 | 14 | func NewChunkReader() *ChunkReader { 15 | return &ChunkReader{} 16 | } 17 | 18 | const ( 19 | inputLimitIdx = 0 20 | inputColIdxOffset = 2 21 | ) 22 | 23 | func (r *ChunkReader) GetLimit(ctx CodeGenContext) value.Value { 24 | idxConst := constant.NewInt(irTypes.I64, int64(inputLimitIdx)) 25 | limitPtr := ctx.Block().NewGetElementPtr(irTypes.NewPointer(irTypes.I64), ctx.Param(), idxConst) 26 | limit := ctx.Block().NewLoad(irTypes.NewPointer(irTypes.I64), limitPtr) 27 | realLimit := ctx.Block().NewPtrToInt(limit, irTypes.I64) 28 | return realLimit 29 | } 30 | 31 | func (r *ChunkReader) ReadInt64(ctx CodeGenContext, colID int, rowID value.Value) value.Value { 32 | idxConst := constant.NewInt(irTypes.I64, int64(colID+inputColIdxOffset)) 33 | colPtrPtr := ctx.Block().NewGetElementPtr(columnPointerType, ctx.Param(), idxConst) 34 | colPtr := ctx.Block().NewLoad(columnPointerType, colPtrPtr) 35 | 36 | addr := ctx.Block().NewGetElementPtr(irTypes.I64, colPtr, rowID) 37 | ret := ctx.Block().NewLoad(irTypes.I64, addr) 38 | return ret 39 | } 40 | 41 | func (r *ChunkReader) ReadDecimal(ctx CodeGenContext, colID int, rowID value.Value) value.Value { 42 | idxConst := constant.NewInt(irTypes.I64, int64(colID+inputColIdxOffset)) 43 | colPtrPtr := ctx.Block().NewGetElementPtr(columnPointerType, ctx.Param(), idxConst) 44 | colPtr := ctx.Block().NewLoad(columnPointerType, colPtrPtr) 45 | decimalPtr := ctx.Block().NewBitCast(colPtr, irTypes.NewPointer(aot.DecimalType)) 46 | 47 | addr := ctx.Block().NewGetElementPtr(aot.DecimalType, decimalPtr, rowID) 48 | return addr 49 | } 50 | -------------------------------------------------------------------------------- /cpp/llvm_bridge.cpp: -------------------------------------------------------------------------------- 1 | #include "llvm_bridge.h" 2 | 3 | #include "TiJIT.h" 4 | #include "helpers.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace llvm; 12 | 13 | #define JIT_FUNC_NAME "jit_main" 14 | 15 | struct GlobalStates { 16 | std::unique_ptr jit; 17 | ThreadSafeContext ctx; 18 | std::mutex lock; 19 | 20 | GlobalStates() 21 | : ctx(std::make_unique()) 22 | { 23 | spdlog::info("llvm_bridge: initializing library"); 24 | llvm::InitializeNativeTarget(); 25 | llvm::InitializeNativeTargetAsmPrinter(); 26 | llvm::InitializeNativeTargetAsmParser(); 27 | 28 | jit = cantFail(TiJIT::Create()); 29 | } 30 | }; 31 | 32 | [[maybe_unused]] static GlobalStates global = GlobalStates(); 33 | 34 | extern "C" void* compileLLVMIR(const char* ir, size_t len) 35 | { 36 | const std::lock_guard lock(global.lock); 37 | auto memBuf = makeMemoryBuffer(ir, len); 38 | auto module = makeModuleFromMemoryBuffer(*global.ctx.getContext(), memBuf->getMemBufferRef()); 39 | module->setDataLayout(global.jit->getDataLayout()); 40 | auto jitMain = module->getFunction(JIT_FUNC_NAME); 41 | 42 | const std::string jitSymbolName = generateFreshJITSymbolName(); 43 | jitMain->setName(jitSymbolName); 44 | 45 | global.jit->addModule(std::move(module)); 46 | auto sym = global.jit->lookup(jitSymbolName); 47 | if (!sym) { 48 | spdlog::error("llvm_bridge: JIT look up symbol {} failed: {}", 49 | jitSymbolName, toString(sym.takeError())); 50 | return nullptr; 51 | } 52 | 53 | spdlog::debug("llvm_bridge: JIT compilation finished. Symbol name: {}, address: {}", 54 | jitSymbolName, (uint64_t)sym->getAddress()); 55 | return (void*)sym->getAddress(); 56 | } -------------------------------------------------------------------------------- /program/machine_code.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | 7 | "github.com/pingcap/errors" 8 | "github.com/pingcap/log" 9 | ) 10 | 11 | type ( 12 | // Arg is an integral type that corresponds to a machine register. 13 | Arg = uintptr 14 | 15 | // Result is the type for return values. 16 | Result = uintptr 17 | 18 | Callable = func(Arg, Arg) Result 19 | ) 20 | 21 | type MachineCode struct { 22 | Code []byte 23 | 24 | // funcPtr is a pointer to executable code in memory 25 | funcPtr []byte 26 | } 27 | 28 | func NewMachineCode(code []byte) *MachineCode { 29 | return &MachineCode{ 30 | Code: code, 31 | } 32 | } 33 | 34 | func (m *MachineCode) mmap() error { 35 | if len(m.Code) == 0 { 36 | log.Panic("code is empty") 37 | } 38 | 39 | funcPtr, err := syscall.Mmap( 40 | -1, 41 | 0, 42 | len(m.Code), 43 | syscall.PROT_READ|syscall.PROT_WRITE|syscall.PROT_EXEC, syscall.MAP_PRIVATE|syscall.MAP_ANONYMOUS, 44 | ) 45 | if err != nil { 46 | return errors.Trace(err) 47 | } 48 | 49 | // Copies the code to an executable memory block 50 | copy(funcPtr, m.Code) 51 | 52 | m.funcPtr = funcPtr 53 | return nil 54 | } 55 | 56 | func (m *MachineCode) Execute(arg0, arg1 Arg) (Result, error) { 57 | if m.funcPtr == nil { 58 | if err := m.mmap(); err != nil { 59 | return 0, errors.Trace(err) 60 | } 61 | } 62 | 63 | unsafeFunc := (uintptr)(unsafe.Pointer(&m.funcPtr)) 64 | executablePtr := *(*Callable)(unsafe.Pointer(&unsafeFunc)) 65 | ret := executablePtr(arg0, arg1) 66 | 67 | return ret, nil 68 | } 69 | 70 | func (m *MachineCode) Release() error { 71 | if m.funcPtr == nil { 72 | return nil 73 | } 74 | 75 | if err := syscall.Munmap(m.funcPtr); err != nil { 76 | return errors.Trace(err) 77 | } 78 | m.funcPtr = nil 79 | return nil 80 | } 81 | 82 | func (m *MachineCode) RawFuncPtr() (uintptr, error) { 83 | if m.funcPtr == nil { 84 | if err := m.mmap(); err != nil { 85 | return 0, errors.Trace(err) 86 | } 87 | } 88 | 89 | return uintptr(unsafe.Pointer(&m.funcPtr[0])), nil 90 | } 91 | -------------------------------------------------------------------------------- /ast/decimal_ops.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "github.com/liuzix/ticompile/gen" 5 | "github.com/liuzix/ticompile/gen/aot" 6 | irTypes "github.com/llir/llvm/ir/types" 7 | "github.com/llir/llvm/ir/value" 8 | "github.com/pingcap/log" 9 | "github.com/pingcap/tidb/parser/opcode" 10 | "go.uber.org/zap" 11 | ) 12 | 13 | type DecimalBinOp struct { 14 | Left Node 15 | Right Node 16 | Op opcode.Op 17 | } 18 | 19 | 20 | func (o *DecimalBinOp) Compile(ctx gen.CodeGenContext) value.Value { 21 | decimalPtrType := irTypes.NewPointer(aot.DecimalType) 22 | 23 | // Type check to help catch error at runtime 24 | leftType, err := o.Left.GetIRType() 25 | if err != nil { 26 | log.Panic("failed to compile", zap.Error(err)) 27 | } 28 | if !decimalPtrType.Equal(leftType) { 29 | log.Panic("type check failed", zap.Any("left-type", leftType)) 30 | } 31 | 32 | rightType, err := o.Left.GetIRType() 33 | if err != nil { 34 | log.Panic("failed to compile", zap.Error(err)) 35 | } 36 | if !decimalPtrType.Equal(rightType) { 37 | log.Panic("type check failed", zap.Any("right-type", rightType)) 38 | } 39 | 40 | switch o.Op { 41 | case opcode.Mul: 42 | return o.compileMul(ctx) 43 | case opcode.Minus: 44 | return o.compileMinus(ctx) 45 | default: 46 | panic("implement me") 47 | } 48 | } 49 | 50 | func (o *DecimalBinOp) compileMul(ctx gen.CodeGenContext) value.Value { 51 | leftVal := o.Left.Compile(ctx) 52 | rightVal := o.Right.Compile(ctx) 53 | stackVar := ctx.Block().NewAlloca(aot.DecimalType) 54 | stackVar.Align = 4 55 | ctx.Block().NewCall(aot.DecimalMulFunction, leftVal, rightVal, stackVar) 56 | return stackVar 57 | } 58 | 59 | func (o *DecimalBinOp) compileMinus(ctx gen.CodeGenContext) value.Value { 60 | leftVal := o.Left.Compile(ctx) 61 | rightVal := o.Right.Compile(ctx) 62 | stackVar := ctx.Block().NewAlloca(aot.DecimalType) 63 | stackVar.Align = 4 64 | ctx.Block().NewCall(aot.DecimalSubFunction, leftVal, rightVal, stackVar) 65 | return stackVar 66 | } 67 | 68 | func (o *DecimalBinOp) GetIRType() (irTypes.Type, error) { 69 | return irTypes.NewPointer(aot.DecimalType), nil 70 | } 71 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/liuzix/ticompile 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/llir/llvm v0.3.4 7 | github.com/pingcap/errors v0.11.5-0.20211224045212-9687c2b0f87c 8 | github.com/pingcap/log v0.0.0-20211215031037-e024ba4eb0ee 9 | github.com/pingcap/tidb v0.0.0-unpublished 10 | github.com/pingcap/tidb/parser v0.0.0-unpublished 11 | github.com/stretchr/testify v1.7.0 12 | go.uber.org/zap v1.19.1 13 | ) 14 | 15 | require ( 16 | github.com/BurntSushi/toml v0.3.1 // indirect 17 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect 18 | github.com/beorn7/perks v1.0.1 // indirect 19 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 20 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect 21 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect 22 | github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect 23 | github.com/danjacques/gofslock v0.0.0-20191023191349-0a45f885bc37 // indirect 24 | github.com/davecgh/go-spew v1.1.1 // indirect 25 | github.com/go-ole/go-ole v1.2.4 // indirect 26 | github.com/gogo/protobuf v1.3.2 // indirect 27 | github.com/golang/protobuf v1.5.2 // indirect 28 | github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 // indirect 29 | github.com/llir/ll v0.0.0-20210719001141-246f2b6b1fa9 // indirect 30 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 31 | github.com/mewmew/float v0.0.0-20201204173432-505706aa38fa // indirect 32 | github.com/opentracing/basictracer-go v1.0.0 // indirect 33 | github.com/opentracing/opentracing-go v1.1.0 // indirect 34 | github.com/pingcap/failpoint v0.0.0-20210316064728-7acb0f0a3dfd // indirect 35 | github.com/pingcap/kvproto v0.0.0-20211207042851-78a55fb8e69c // indirect 36 | github.com/pingcap/tipb v0.0.0-20211227115224-a06a85f9d2a5 // indirect 37 | github.com/pkg/errors v0.9.1 // indirect 38 | github.com/pmezard/go-difflib v1.0.0 // indirect 39 | github.com/prometheus/client_golang v1.5.1 // indirect 40 | github.com/prometheus/client_model v0.2.0 // indirect 41 | github.com/prometheus/common v0.9.1 // indirect 42 | github.com/prometheus/procfs v0.0.8 // indirect 43 | github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect 44 | github.com/shirou/gopsutil v3.21.3+incompatible // indirect 45 | github.com/tikv/client-go/v2 v2.0.0-rc.0.20211229051614-62d6b4a2e8f7 // indirect 46 | github.com/tikv/pd v1.1.0-beta.0.20211118054146-02848d2660ee // indirect 47 | github.com/uber/jaeger-client-go v2.22.1+incompatible // indirect 48 | github.com/uber/jaeger-lib v2.4.1+incompatible // indirect 49 | go.etcd.io/etcd v0.5.0-alpha.5.0.20210512015243-d19fbe541bf9 // indirect 50 | go.uber.org/atomic v1.9.0 // indirect 51 | go.uber.org/multierr v1.7.0 // indirect 52 | golang.org/x/mod v0.5.1 // indirect 53 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect 54 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect 55 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect 56 | golang.org/x/text v0.3.7 // indirect 57 | golang.org/x/tools v0.1.8 // indirect 58 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 59 | google.golang.org/genproto v0.0.0-20210825212027-de86158e7fda // indirect 60 | google.golang.org/grpc v1.40.0 // indirect 61 | google.golang.org/protobuf v1.27.1 // indirect 62 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect 63 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 64 | ) 65 | 66 | replace ( 67 | github.com/liuzix/ticompile => ./ 68 | github.com/pingcap/tidb => ./tidb 69 | github.com/pingcap/tidb/parser => ./tidb/parser 70 | ) 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TiCompile Project 2 | 3 | _Author: Zixiong Liu_ 4 | 5 | ## Introduction 6 | 7 | The TiCompile project aims to bring JIT (just-in-time compilation) to TiDB's computation layer. This project will add JIT support in TiDB so that it can compile the execution plan of computation-intensive queries into machine code, which will be cached for repeated use. 8 | 9 | In the first stage of the project, we plan to support: 10 | 11 | 1. JIT of expressions 12 | 2. JIT of aggregations 13 | 3. JIT of hash-join (challenge) 14 | 15 | The goal of this project is to explore the possibility of accelerating the computations done by TiDB, especially for situations with complex expressions. **Hopefully, this project can produce some valuable results so that we can make TiDB a better candidate in some computation-intensive scenarios.** 16 | 17 | ## Design Details 18 | 19 | The compilation of an execution plan is done as follows: 20 | 1. Convert the execution plan to LLVM IR (intermediate representation), which is a low-level language in SSA (static single assignment form). This is done by pure Go code by using the library [llir/llvm](https://github.com/llir/llvm). 21 | 22 | 2. The resulted LLVM IR is then stored in Bitcode (binary) format and then passed to a _LLVMBridge_ library written in C++, which in turn utilizes the LLVM library to emit machine code and store the machine code in an executable region of memory. The _LLVMBridge_ returns a function pointer to Go code. The invocation of C++ code is done through CGO. The performance of CGO is of little concern because the cost of converting the LLVM IR to machine code would dominate. 23 | 24 | 3. The Go code will cache the function pointer, and invoke the function pointer when it is needed. This invocation here is done **without** CGO by directly executing a `call` instruction in Go. Since the compiled function is purely computational (i.e. without IO and other interaction with the OS), calling it directly within a goroutine context would be uncomplicated. 25 | 26 | ### Why LLVM? 27 | LLVM is a mature compiler infrastructure library friendly with JIT. Using LLVM brings us two advantages. 28 | 29 | 1. We can use LLVM IR, which has a human-readable format so that debugging code generation would be easier, and it is also more structural than pure assembly, making it easier to be generated by Go functions. Also, LLVM IR is platform-neutral, making it easier to implement support for both x86-64 and Arm, and potentially other architectures. 30 | 31 | 2. Using LLVM makes it possible to apply ready-to-use optimization passes to the generated code, without having to implement these optimizations by ourselves. 32 | 33 | In summary, by utilizing a mature tool, we free ourselves from having to implement a cross-platform compiler from ground up, so that we can focus on how to make the JIT mechanism be more compatible with our database system (TiDB). 34 | 35 | ### Why not WASM? 36 | WASM may seem to be a good alternative, and it is a popular language to be embedded into a large project. We are not choosing to compile to WASM because the semantics of WASM are extremely similar to the machine code, so the cost (both to develop and to run) to compile an execution plan to WASM is similar to that of compiling to machine code. Since machine code more low-level, it would get better performance (however small an advantage it may be), we may as well directly compile to machine code. 37 | 38 | 39 | ## References 40 | - [Everything You Always Wanted to Know About 41 | Compiled and Vectorized Queries But Were Afraid to Ask](https://www.vldb.org/pvldb/vol11/p2209-kersten.pdf) 42 | - [Fast Compilation and Execution of SQL Queries with 43 | WebAssembly](https://arxiv.org/pdf/2104.15098.pdf) 44 | - [LLVM Tutorial](https://llvm.org/docs/tutorial/) -------------------------------------------------------------------------------- /gen/code_gen_context.go: -------------------------------------------------------------------------------- 1 | package gen 2 | 3 | import ( 4 | "github.com/llir/llvm/ir" 5 | "github.com/llir/llvm/ir/constant" 6 | "github.com/llir/llvm/ir/enum" 7 | "github.com/llir/llvm/ir/types" 8 | "github.com/llir/llvm/ir/value" 9 | ) 10 | 11 | const ( 12 | jitMainFuncName = "jit_main" 13 | ) 14 | 15 | type CodeGenContext interface { 16 | Module() *ir.Module 17 | Block() *ir.Block 18 | SetBlock(block *ir.Block) 19 | Param() value.Value 20 | Loop(limit value.Value) *LoopCodeGenContext 21 | RelocateInputIdx(placeholder string) (idx int) 22 | InputReader() *ChunkReader 23 | OutputWriter() *ColumnWriter 24 | } 25 | 26 | type BaseCodeGenContext struct { 27 | module *ir.Module 28 | MainFunc *ir.Func 29 | block *ir.Block 30 | param value.Value 31 | inputReader *ChunkReader 32 | outputWriter *ColumnWriter 33 | 34 | InputIdxMap map[string]int 35 | } 36 | 37 | func NewCodeGenContext(blockName string) *BaseCodeGenContext { 38 | module := ir.NewModule() 39 | 40 | inputPointerVecType := types.NewPointer(types.I64) 41 | inputParam := ir.NewParam("jit_input", types.NewPointer(inputPointerVecType)) 42 | mainFunc := module.NewFunc( 43 | jitMainFuncName, 44 | types.I64, 45 | inputParam) 46 | block := mainFunc.NewBlock(blockName) 47 | 48 | ret := &BaseCodeGenContext{ 49 | module: module, 50 | MainFunc: mainFunc, 51 | block: block, 52 | param: inputParam, 53 | } 54 | return ret 55 | } 56 | 57 | func NewCodeGenContextWithChunkReader() *BaseCodeGenContext { 58 | ctx := NewCodeGenContext("") 59 | chunkReader := NewChunkReader() 60 | ctx.inputReader = chunkReader 61 | 62 | columnWriter := NewColumnWriter(ctx) 63 | ctx.outputWriter = columnWriter 64 | return ctx 65 | } 66 | 67 | func (c *BaseCodeGenContext) Module() *ir.Module { 68 | return c.module 69 | } 70 | 71 | func (c *BaseCodeGenContext) Block() *ir.Block { 72 | return c.block 73 | } 74 | 75 | func (c *BaseCodeGenContext) SetBlock(block *ir.Block) { 76 | c.block = block 77 | } 78 | 79 | func (c *BaseCodeGenContext) Param() value.Value { 80 | return c.param 81 | } 82 | 83 | func (c *BaseCodeGenContext) RelocateInputIdx(placeholder string) (idx int) { 84 | if index, ok := c.InputIdxMap[placeholder]; ok { 85 | return index 86 | } 87 | return -1 88 | } 89 | 90 | func (c *BaseCodeGenContext) InputReader() *ChunkReader { 91 | return c.inputReader 92 | } 93 | 94 | func (c *BaseCodeGenContext) OutputWriter() *ColumnWriter { 95 | return c.outputWriter 96 | } 97 | 98 | type LoopCodeGenContext struct { 99 | CodeGenContext 100 | 101 | loopBlock *ir.Block 102 | loopCounter value.Value 103 | nextLoopCounter value.Value 104 | loopLimit value.Value 105 | } 106 | 107 | // Loop returns a context that can be used in a loop. 108 | // ref: https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.html#llvm-ir-for-the-for-loop 109 | func (c *BaseCodeGenContext) Loop(limit value.Value) *LoopCodeGenContext { 110 | loopBlock := c.MainFunc.NewBlock("") 111 | afterLoopBlock := c.MainFunc.NewBlock("") 112 | 113 | c.Block().NewBr(loopBlock) 114 | preLoopBlock := c.Block() 115 | c.SetBlock(afterLoopBlock) 116 | 117 | loopCtx := &LoopCodeGenContext{ 118 | CodeGenContext: c, 119 | loopBlock: loopBlock, 120 | } 121 | 122 | initLoopVar := constant.NewInt(types.I64, 0) 123 | phiNode := loopBlock.NewPhi( 124 | ir.NewIncoming(initLoopVar, preLoopBlock)) 125 | loopCtx.loopCounter = phiNode 126 | loopVarIncConst := constant.NewInt(types.I64, 1) 127 | loopCtx.nextLoopCounter = loopBlock.NewAdd(loopCtx.loopCounter, loopVarIncConst) 128 | phiNode.Incs = append(phiNode.Incs, ir.NewIncoming(loopCtx.nextLoopCounter, loopBlock)) 129 | loopCtx.loopLimit = limit 130 | 131 | return loopCtx 132 | } 133 | 134 | func (c *LoopCodeGenContext) Block() *ir.Block { 135 | return c.loopBlock 136 | } 137 | 138 | func (c *LoopCodeGenContext) LoopVar() value.Value { 139 | return c.loopCounter 140 | } 141 | 142 | func (c *LoopCodeGenContext) FinishLoop() { 143 | cond := c.loopBlock.NewICmp(enum.IPredEQ, c.nextLoopCounter, c.loopLimit) 144 | c.loopBlock.NewCondBr(cond, c.CodeGenContext.Block(), c.loopBlock) 145 | } 146 | -------------------------------------------------------------------------------- /cpp/TiJIT.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace llvm; 26 | using namespace llvm::orc; 27 | 28 | class TiJIT { 29 | ExecutionSession es; 30 | RTDyldObjectLinkingLayer objectLayer; 31 | IRCompileLayer compileLayer; 32 | IRTransformLayer transformLayer; 33 | DataLayout dl; 34 | MangleAndInterner mangle; 35 | JITDylib& mainJD; 36 | ThreadSafeContext ctx; 37 | 38 | public: 39 | TiJIT(JITTargetMachineBuilder JTMB, DataLayout DL) 40 | : objectLayer(es, 41 | []() { return std::make_unique(); }) 42 | , es(std::move(SelfExecutorProcessControl::Create().get())) 43 | , compileLayer(es, objectLayer, std::make_unique(std::move(JTMB))) 44 | , transformLayer(es, compileLayer, optimizeModule) 45 | , dl(DL) 46 | , mangle(es, 47 | this->dl) 48 | , mainJD(es.createBareJITDylib("
")) 49 | , ctx(std::make_unique()) 50 | { 51 | mainJD.addGenerator( 52 | cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( 53 | DL.getGlobalPrefix()))); 54 | } 55 | 56 | static Expected 57 | optimizeModule(ThreadSafeModule TSM, const MaterializationResponsibility &R) { 58 | TSM.withModuleDo([](Module &M) { 59 | auto PM = std::make_unique(); 60 | PM->add(createFunctionInliningPass()); 61 | PM->run(M); 62 | 63 | // Create a function pass manager. 64 | auto FPM = std::make_unique(&M); 65 | // Add some optimizations. 66 | FPM->add(createSROAPass()); 67 | FPM->add(createPromoteMemoryToRegisterPass()); 68 | FPM->add(createLICMPass()); 69 | FPM->add(createLoopSimplifyPass()); 70 | FPM->add(createInstructionCombiningPass()); 71 | FPM->add(createReassociatePass()); 72 | FPM->add(createAggressiveDCEPass()); 73 | FPM->add(createLCSSAPass()); 74 | FPM->add(createLoopVectorizePass()); 75 | FPM->add(createSLPVectorizerPass()); 76 | FPM->add(createLoopUnrollPass()); 77 | FPM->doInitialization(); 78 | 79 | // Run the optimizations over all functions in the module being added to 80 | // the JIT. 81 | for (auto &F : M) 82 | FPM->run(F); 83 | }); 84 | 85 | return std::move(TSM); 86 | } 87 | 88 | static Expected> Create() 89 | { 90 | auto builder = JITTargetMachineBuilder(Triple("x86_64-unknown-linux")); 91 | builder.setCPU("znver3"); 92 | auto triple = builder.getTargetTriple(); 93 | spdlog::info("triple {}", triple.str()); 94 | auto layout = DataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i32:32:32-i8:8:8-i1:8:8-f80:128-n8:16:32:64-S128"); 95 | return std::make_unique(std::move(builder), std::move(layout)); 96 | } 97 | 98 | const DataLayout& getDataLayout() const { return dl; } 99 | 100 | JITDylib& getMainJITDylib() { return mainJD; } 101 | 102 | void addModule(std::unique_ptr M) 103 | { 104 | cantFail(transformLayer.add(this->mainJD, ThreadSafeModule(std::move(M), ctx))); 105 | } 106 | 107 | bool removeModule(StringRef name) 108 | { 109 | auto err = mainJD.remove({ mangle(name.str()) }); 110 | if (err) { 111 | spdlog::error("llvm_bridge: failed to remove module: {}", 112 | toString(std::move(err))); 113 | return false; 114 | } 115 | return true; 116 | } 117 | 118 | Expected lookup(StringRef Name) 119 | { 120 | return es.lookup({ &mainJD }, mangle(Name.str())); 121 | } 122 | }; -------------------------------------------------------------------------------- /gen/aot/main/helper.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 PingCAP, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "math" 19 | "strconv" 20 | "strings" 21 | "unicode" 22 | ) 23 | 24 | // RoundFloat rounds float val to the nearest even integer value with float64 format, like MySQL Round function. 25 | // RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html 26 | // so rounding use "round to nearest even". 27 | // e.g, 1.5 -> 2, -1.5 -> -2. 28 | func RoundFloat(f float64) float64 { 29 | return math.RoundToEven(f) 30 | } 31 | 32 | // Round rounds the argument f to dec decimal places. 33 | // dec defaults to 0 if not specified. dec can be negative 34 | // to cause dec digits left of the decimal point of the 35 | // value f to become zero. 36 | func Round(f float64, dec int) float64 { 37 | shift := math.Pow10(dec) 38 | tmp := f * shift 39 | if math.IsInf(tmp, 0) { 40 | return f 41 | } 42 | result := RoundFloat(tmp) / shift 43 | if math.IsNaN(result) { 44 | return 0 45 | } 46 | return result 47 | } 48 | 49 | // Truncate truncates the argument f to dec decimal places. 50 | // dec defaults to 0 if not specified. dec can be negative 51 | // to cause dec digits left of the decimal point of the 52 | // value f to become zero. 53 | func Truncate(f float64, dec int) float64 { 54 | shift := math.Pow10(dec) 55 | tmp := f * shift 56 | if math.IsInf(tmp, 0) { 57 | return f 58 | } 59 | return math.Trunc(tmp) / shift 60 | } 61 | 62 | // GetMaxFloat gets the max float for given flen and decimal. 63 | func GetMaxFloat(flen int, decimal int) float64 { 64 | intPartLen := flen - decimal 65 | f := math.Pow10(intPartLen) 66 | f -= math.Pow10(-decimal) 67 | return f 68 | } 69 | 70 | // TruncateFloat tries to truncate f. 71 | // If the result exceeds the max/min float that flen/decimal allowed, returns the max/min float allowed. 72 | func TruncateFloat(f float64, flen int, decimal int) (float64, ErrNo) { 73 | if math.IsNaN(f) { 74 | // nan returns 0 75 | return 0, ErrOverflow 76 | } 77 | 78 | maxF := GetMaxFloat(flen, decimal) 79 | 80 | if !math.IsInf(f, 0) { 81 | f = Round(f, decimal) 82 | } 83 | 84 | var err ErrNo 85 | if f > maxF { 86 | f = maxF 87 | err = ErrOverflow 88 | } else if f < -maxF { 89 | f = -maxF 90 | err = ErrOverflow 91 | } 92 | 93 | return f, err 94 | } 95 | 96 | // TruncateFloatToString is used to truncate float to string where dec is the number of digits after the decimal point. 97 | func TruncateFloatToString(f float64, dec int) string { 98 | f = Truncate(f, dec) 99 | return strconv.FormatFloat(f, 'f', -1, 64) 100 | } 101 | 102 | func isSpace(c byte) bool { 103 | return c == ' ' || c == '\t' 104 | } 105 | 106 | func isDigit(c byte) bool { 107 | return c >= '0' && c <= '9' 108 | } 109 | 110 | // Returns true if the given byte is an ASCII punctuation character (printable and non-alphanumeric). 111 | func isPunctuation(c byte) bool { 112 | return (c >= 0x21 && c <= 0x2F) || (c >= 0x3A && c <= 0x40) || (c >= 0x5B && c <= 0x60) || (c >= 0x7B && c <= 0x7E) 113 | } 114 | 115 | func myMax(a, b int) int { 116 | if a > b { 117 | return a 118 | } 119 | return b 120 | } 121 | 122 | func myMaxInt8(a, b int8) int8 { 123 | if a > b { 124 | return a 125 | } 126 | return b 127 | } 128 | 129 | func myMin(a, b int) int { 130 | if a < b { 131 | return a 132 | } 133 | return b 134 | } 135 | 136 | func myMinInt8(a, b int8) int8 { 137 | if a < b { 138 | return a 139 | } 140 | return b 141 | } 142 | 143 | const ( 144 | maxUint = uint64(math.MaxUint64) 145 | uintCutOff = maxUint/uint64(10) + 1 146 | intCutOff = uint64(math.MaxInt64) + 1 147 | ) 148 | 149 | // strToInt converts a string to an integer in best effort. 150 | func strToInt(str string) (int64, ErrNo) { 151 | str = strings.TrimSpace(str) 152 | if len(str) == 0 { 153 | return 0, ErrTruncated 154 | } 155 | negative := false 156 | i := 0 157 | if str[i] == '-' { 158 | negative = true 159 | i++ 160 | } else if str[i] == '+' { 161 | i++ 162 | } 163 | 164 | var ( 165 | err ErrNo 166 | hasNum = false 167 | ) 168 | r := uint64(0) 169 | for ; i < len(str); i++ { 170 | if !unicode.IsDigit(rune(str[i])) { 171 | err = ErrTruncated 172 | break 173 | } 174 | hasNum = true 175 | if r >= uintCutOff { 176 | r = 0 177 | err = ErrBadNumber 178 | break 179 | } 180 | r = r * uint64(10) 181 | 182 | r1 := r + uint64(str[i]-'0') 183 | if r1 < r || r1 > maxUint { 184 | r = 0 185 | err = ErrBadNumber 186 | break 187 | } 188 | r = r1 189 | } 190 | if !hasNum { 191 | err = ErrTruncated 192 | } 193 | 194 | if !negative && r >= intCutOff { 195 | return math.MaxInt64, ErrBadNumber 196 | } 197 | 198 | if negative && r > intCutOff { 199 | return math.MinInt64, ErrBadNumber 200 | } 201 | 202 | if negative { 203 | r = -r 204 | } 205 | return int64(r), err 206 | } 207 | 208 | // DecimalLength2Precision gets the precision. 209 | func DecimalLength2Precision(length int, scale int, hasUnsignedFlag bool) int { 210 | if scale > 0 { 211 | length-- 212 | } 213 | if hasUnsignedFlag || length > 0 { 214 | length-- 215 | } 216 | return length 217 | } 218 | 219 | // Precision2LengthNoTruncation gets the length. 220 | func Precision2LengthNoTruncation(length int, scale int, hasUnsignedFlag bool) int { 221 | if scale > 0 { 222 | length++ 223 | } 224 | if hasUnsignedFlag || length > 0 { 225 | length++ 226 | } 227 | return length 228 | } 229 | -------------------------------------------------------------------------------- /ast/decimal_opt_test.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "runtime" 5 | "testing" 6 | "unsafe" 7 | 8 | "github.com/liuzix/ticompile/compile" 9 | "github.com/liuzix/ticompile/gen" 10 | "github.com/liuzix/ticompile/gen/aot" 11 | "github.com/llir/llvm/ir/constant" 12 | irTypes "github.com/llir/llvm/ir/types" 13 | "github.com/llir/llvm/ir/value" 14 | "github.com/pingcap/log" 15 | "github.com/pingcap/tidb/parser/mysql" 16 | "github.com/pingcap/tidb/parser/opcode" 17 | "github.com/pingcap/tidb/parser/types" 18 | tidbTypes "github.com/pingcap/tidb/types" 19 | "github.com/pingcap/tidb/util/chunk" 20 | "github.com/stretchr/testify/require" 21 | "go.uber.org/zap" 22 | ) 23 | 24 | type oneDecimalNode struct { 25 | val value.Value 26 | } 27 | 28 | func (n *oneDecimalNode) Compile(ctx gen.CodeGenContext) value.Value { 29 | return n.val 30 | } 31 | 32 | func (n *oneDecimalNode) GetIRType() (irTypes.Type, error) { 33 | return irTypes.NewPointer(aot.DecimalType), nil 34 | } 35 | 36 | func TestDecimalBinOp(t *testing.T) { 37 | chunkTypes := []*types.FieldType{ 38 | types.NewFieldType(mysql.TypeNewDecimal), 39 | types.NewFieldType(mysql.TypeNewDecimal), 40 | types.NewFieldType(mysql.TypeNewDecimal)} 41 | inputChunk := chunk.New(chunkTypes, 1024, 1024) 42 | 43 | var dec tidbTypes.MyDecimal 44 | for i := 0; i < 100; i++ { 45 | dec.FromInt(int64(i)) 46 | inputChunk.AppendMyDecimal(0, &dec) 47 | inputChunk.AppendMyDecimal(1, &dec) 48 | } 49 | inputChunk.Column(2).ResizeDecimal(100, false) 50 | 51 | codeGenCtx := gen.NewCodeGenContextWithChunkReader() 52 | val1 := codeGenCtx.InputReader().ReadDecimal(codeGenCtx, 0, constant.NewInt(irTypes.I64, 5)) 53 | val2 := codeGenCtx.InputReader().ReadDecimal(codeGenCtx, 1, constant.NewInt(irTypes.I64, 6)) 54 | opNode := &DecimalBinOp{ 55 | Left: &oneDecimalNode{val1}, 56 | Right: &oneDecimalNode{val2}, 57 | Op: opcode.Mul, 58 | } 59 | resultVal := opNode.Compile(codeGenCtx) 60 | codeGenCtx.OutputWriter().PutDecimal(codeGenCtx, constant.NewInt(irTypes.I64, 0), resultVal) 61 | codeGenCtx.Block().NewRet(constant.NewInt(irTypes.I64, 0)) 62 | 63 | asmText := aot.DecimalModule.String() 64 | asmText += codeGenCtx.Module().String() 65 | log.Info("compiled IR", zap.String("asm", asmText)) 66 | 67 | fn := compile.LLVMCompileIR([]byte(asmText)) 68 | inputVec := []uintptr{ 69 | 0, 70 | uintptr(unsafe.Pointer(&inputChunk.Column(2).Int64s()[0])), 71 | uintptr(unsafe.Pointer(&inputChunk.Column(0).Int64s()[0])), 72 | uintptr(unsafe.Pointer(&inputChunk.Column(1).Int64s()[0])), 73 | } 74 | inputParam := uintptr(unsafe.Pointer(&inputVec[0])) 75 | log.Info("input", 76 | zap.Uintptr("ptr", inputParam), 77 | zap.Any("vec", inputVec)) 78 | res, err := fn(inputParam) 79 | require.NoError(t, err) 80 | require.Equal(t, uintptr(0), res) 81 | 82 | resultDec := inputChunk.Column(2).GetDecimal(0) 83 | resultInt, err := resultDec.ToInt() 84 | require.NoError(t, err) 85 | require.Equal(t, int64(30), resultInt) 86 | } 87 | 88 | func TestDecimalMulLoop(t *testing.T) { 89 | decimalMulLoop(10000) 90 | } 91 | 92 | func decimalMulLoop(N int) { 93 | chunkTypes := []*types.FieldType{ 94 | types.NewFieldType(mysql.TypeNewDecimal), 95 | types.NewFieldType(mysql.TypeNewDecimal), 96 | types.NewFieldType(mysql.TypeNewDecimal)} 97 | inputChunk := chunk.New(chunkTypes, N, N) 98 | var dec tidbTypes.MyDecimal 99 | for i := 0; i < N; i++ { 100 | dec.FromInt(int64(i)) 101 | inputChunk.AppendMyDecimal(0, &dec) 102 | inputChunk.AppendMyDecimal(1, &dec) 103 | } 104 | inputChunk.Column(2).ResizeDecimal(N, false) 105 | 106 | codeGenCtx := gen.NewCodeGenContextWithChunkReader() 107 | loopCtx := codeGenCtx.Loop(constant.NewInt(irTypes.I64, int64(N))) 108 | 109 | val1 := loopCtx.InputReader().ReadDecimal(loopCtx, 0, loopCtx.LoopVar()) 110 | val2 := loopCtx.InputReader().ReadDecimal(loopCtx, 1, loopCtx.LoopVar()) 111 | opNode := &DecimalBinOp{ 112 | Left: &oneDecimalNode{val1}, 113 | Right: &oneDecimalNode{val2}, 114 | Op: opcode.Mul, 115 | } 116 | resultVal := opNode.Compile(loopCtx) 117 | loopCtx.OutputWriter().PutDecimal(loopCtx, loopCtx.LoopVar(), resultVal) 118 | loopCtx.FinishLoop() 119 | codeGenCtx.Block().NewRet(constant.NewInt(irTypes.I64, 0)) 120 | 121 | asmText := aot.DecimalModule.String() 122 | asmText += codeGenCtx.Module().String() 123 | 124 | input0 := unsafe.Pointer(&inputChunk.Column(2).Int64s()[0]) 125 | input1 := unsafe.Pointer(&inputChunk.Column(0).Int64s()[0]) 126 | input2 := unsafe.Pointer(&inputChunk.Column(1).Int64s()[0]) 127 | fn := compile.LLVMCompileIR([]byte(asmText)) 128 | inputVec := []uintptr{ 129 | 0, 130 | uintptr(input0), 131 | uintptr(input1), 132 | uintptr(input2), 133 | } 134 | _, _ = fn(uintptr(unsafe.Pointer(&inputVec[0]))) 135 | runtime.KeepAlive(inputChunk) 136 | runtime.KeepAlive(input0) 137 | runtime.KeepAlive(input1) 138 | runtime.KeepAlive(input2) 139 | runtime.KeepAlive(inputVec) 140 | } 141 | 142 | func BenchmarkDecimalMul(b *testing.B) { 143 | N := b.N 144 | 145 | chunkTypes := []*types.FieldType{ 146 | types.NewFieldType(mysql.TypeNewDecimal), 147 | types.NewFieldType(mysql.TypeNewDecimal), 148 | types.NewFieldType(mysql.TypeNewDecimal)} 149 | inputChunk := chunk.New(chunkTypes, N, N) 150 | var dec tidbTypes.MyDecimal 151 | for i := 0; i < N; i++ { 152 | dec.FromInt(int64(i)) 153 | inputChunk.AppendMyDecimal(0, &dec) 154 | inputChunk.AppendMyDecimal(1, &dec) 155 | } 156 | inputChunk.Column(2).ResizeDecimal(N, false) 157 | 158 | codeGenCtx := gen.NewCodeGenContextWithChunkReader() 159 | loopCtx := codeGenCtx.Loop(constant.NewInt(irTypes.I64, int64(N))) 160 | 161 | val1 := loopCtx.InputReader().ReadDecimal(loopCtx, 0, loopCtx.LoopVar()) 162 | val2 := loopCtx.InputReader().ReadDecimal(loopCtx, 1, loopCtx.LoopVar()) 163 | opNode := &DecimalBinOp{ 164 | Left: &oneDecimalNode{val1}, 165 | Right: &oneDecimalNode{val2}, 166 | Op: opcode.Mul, 167 | } 168 | resultVal := opNode.Compile(loopCtx) 169 | loopCtx.OutputWriter().PutDecimal(loopCtx, loopCtx.LoopVar(), resultVal) 170 | loopCtx.FinishLoop() 171 | codeGenCtx.Block().NewRet(constant.NewInt(irTypes.I64, 0)) 172 | 173 | asmText := aot.DecimalModule.String() 174 | asmText += codeGenCtx.Module().String() 175 | log.Info("compiled IR", zap.String("asm", asmText)) 176 | 177 | input0 := unsafe.Pointer(&inputChunk.Column(2).Int64s()[0]) 178 | input1 := unsafe.Pointer(&inputChunk.Column(0).Int64s()[0]) 179 | input2 := unsafe.Pointer(&inputChunk.Column(1).Int64s()[0]) 180 | fn := compile.LLVMCompileIR([]byte(asmText)) 181 | inputVec := []uintptr{ 182 | 0, 183 | uintptr(input0), 184 | uintptr(input1), 185 | uintptr(input2), 186 | } 187 | b.ResetTimer() 188 | res, err := fn(uintptr(unsafe.Pointer(&inputVec[0]))) 189 | if err != nil { 190 | b.FailNow() 191 | } 192 | if res != 0 { 193 | b.FailNow() 194 | } 195 | runtime.KeepAlive(inputChunk) 196 | runtime.KeepAlive(input0) 197 | runtime.KeepAlive(input1) 198 | runtime.KeepAlive(input2) 199 | runtime.KeepAlive(inputVec) 200 | } 201 | 202 | 203 | func TestDecimalStructSize(t *testing.T) { 204 | ctx := gen.NewCodeGenContext("") 205 | val := ctx.Block().NewAlloca(aot.DecimalType) 206 | offSetPtr := ctx.Block().NewGetElementPtr( 207 | aot.DecimalType, 208 | val, 209 | constant.NewInt(irTypes.I64, 1)) 210 | offSet := ctx.Block().NewPtrToInt(offSetPtr, irTypes.I64) 211 | origin := ctx.Block().NewPtrToInt(val, irTypes.I64) 212 | diff := ctx.Block().NewSub(offSet, origin) 213 | ctx.Block().NewRet(diff) 214 | 215 | asm := aot.DecimalModule.String() + ctx.Module().String() 216 | fn := compile.LLVMCompileIR([]byte(asm)) 217 | ret, err := fn(0) 218 | require.NoError(t, err) 219 | require.Equal(t, uintptr(40), ret) 220 | } -------------------------------------------------------------------------------- /tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/liuzix/ticompile/tools 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/golangci/golangci-lint v1.43.0 7 | mvdan.cc/gofumpt v0.1.1 8 | ) 9 | 10 | require ( 11 | 4d63.com/gochecknoglobals v0.1.0 // indirect 12 | github.com/Antonboom/errname v0.1.5 // indirect 13 | github.com/Antonboom/nilnil v0.1.0 // indirect 14 | github.com/BurntSushi/toml v0.4.1 // indirect 15 | github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect 16 | github.com/Masterminds/semver v1.5.0 // indirect 17 | github.com/OpenPeeDeeP/depguard v1.0.1 // indirect 18 | github.com/alexkohler/prealloc v1.0.0 // indirect 19 | github.com/ashanbrown/forbidigo v1.2.0 // indirect 20 | github.com/ashanbrown/makezero v0.0.0-20210520155254-b6261585ddde // indirect 21 | github.com/beorn7/perks v1.0.1 // indirect 22 | github.com/bkielbasa/cyclop v1.2.0 // indirect 23 | github.com/blizzy78/varnamelen v0.3.0 // indirect 24 | github.com/bombsimon/wsl/v3 v3.3.0 // indirect 25 | github.com/breml/bidichk v0.1.1 // indirect 26 | github.com/butuzov/ireturn v0.1.1 // indirect 27 | github.com/cespare/xxhash/v2 v2.1.1 // indirect 28 | github.com/charithe/durationcheck v0.0.9 // indirect 29 | github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect 30 | github.com/daixiang0/gci v0.2.9 // indirect 31 | github.com/davecgh/go-spew v1.1.1 // indirect 32 | github.com/denis-tingajkin/go-header v0.4.2 // indirect 33 | github.com/esimonov/ifshort v1.0.3 // indirect 34 | github.com/ettle/strcase v0.1.1 // indirect 35 | github.com/fatih/color v1.13.0 // indirect 36 | github.com/fatih/structtag v1.2.0 // indirect 37 | github.com/fsnotify/fsnotify v1.5.1 // indirect 38 | github.com/fzipp/gocyclo v0.3.1 // indirect 39 | github.com/go-critic/go-critic v0.6.1 // indirect 40 | github.com/go-toolsmith/astcast v1.0.0 // indirect 41 | github.com/go-toolsmith/astcopy v1.0.0 // indirect 42 | github.com/go-toolsmith/astequal v1.0.1 // indirect 43 | github.com/go-toolsmith/astfmt v1.0.0 // indirect 44 | github.com/go-toolsmith/astp v1.0.0 // indirect 45 | github.com/go-toolsmith/strparse v1.0.0 // indirect 46 | github.com/go-toolsmith/typep v1.0.2 // indirect 47 | github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect 48 | github.com/gobwas/glob v0.2.3 // indirect 49 | github.com/gofrs/flock v0.8.1 // indirect 50 | github.com/golang/protobuf v1.5.2 // indirect 51 | github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect 52 | github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect 53 | github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 // indirect 54 | github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a // indirect 55 | github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect 56 | github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect 57 | github.com/golangci/misspell v0.3.5 // indirect 58 | github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect 59 | github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect 60 | github.com/google/go-cmp v0.5.6 // indirect 61 | github.com/gordonklaus/ineffassign v0.0.0-20210225214923-2e10b2664254 // indirect 62 | github.com/gostaticanalysis/analysisutil v0.7.1 // indirect 63 | github.com/gostaticanalysis/comment v1.4.2 // indirect 64 | github.com/gostaticanalysis/forcetypeassert v0.0.0-20200621232751-01d4955beaa5 // indirect 65 | github.com/gostaticanalysis/nilerr v0.1.1 // indirect 66 | github.com/hashicorp/errwrap v1.0.0 // indirect 67 | github.com/hashicorp/go-multierror v1.1.1 // indirect 68 | github.com/hashicorp/hcl v1.0.0 // indirect 69 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 70 | github.com/jgautheron/goconst v1.5.1 // indirect 71 | github.com/jingyugao/rowserrcheck v1.1.1 // indirect 72 | github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect 73 | github.com/julz/importas v0.0.0-20210419104244-841f0c0fe66d // indirect 74 | github.com/kisielk/errcheck v1.6.0 // indirect 75 | github.com/kisielk/gotool v1.0.0 // indirect 76 | github.com/kulti/thelper v0.4.0 // indirect 77 | github.com/kunwardeep/paralleltest v1.0.3 // indirect 78 | github.com/kyoh86/exportloopref v0.1.8 // indirect 79 | github.com/ldez/gomoddirectives v0.2.2 // indirect 80 | github.com/ldez/tagliatelle v0.2.0 // indirect 81 | github.com/magiconair/properties v1.8.5 // indirect 82 | github.com/maratori/testpackage v1.0.1 // indirect 83 | github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect 84 | github.com/mattn/go-colorable v0.1.11 // indirect 85 | github.com/mattn/go-isatty v0.0.14 // indirect 86 | github.com/mattn/go-runewidth v0.0.9 // indirect 87 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 88 | github.com/mbilski/exhaustivestruct v1.2.0 // indirect 89 | github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect 90 | github.com/mgechev/revive v1.1.2 // indirect 91 | github.com/mitchellh/go-homedir v1.1.0 // indirect 92 | github.com/mitchellh/mapstructure v1.4.2 // indirect 93 | github.com/moricho/tparallel v0.2.1 // indirect 94 | github.com/nakabonne/nestif v0.3.1 // indirect 95 | github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect 96 | github.com/nishanths/exhaustive v0.2.3 // indirect 97 | github.com/nishanths/predeclared v0.2.1 // indirect 98 | github.com/olekukonko/tablewriter v0.0.5 // indirect 99 | github.com/pelletier/go-toml v1.9.4 // indirect 100 | github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect 101 | github.com/pkg/errors v0.9.1 // indirect 102 | github.com/pmezard/go-difflib v1.0.0 // indirect 103 | github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349 // indirect 104 | github.com/prometheus/client_golang v1.7.1 // indirect 105 | github.com/prometheus/client_model v0.2.0 // indirect 106 | github.com/prometheus/common v0.10.0 // indirect 107 | github.com/prometheus/procfs v0.6.0 // indirect 108 | github.com/quasilyte/go-ruleguard v0.3.13 // indirect 109 | github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect 110 | github.com/ryancurrah/gomodguard v1.2.3 // indirect 111 | github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect 112 | github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect 113 | github.com/securego/gosec/v2 v2.9.1 // indirect 114 | github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect 115 | github.com/sirupsen/logrus v1.8.1 // indirect 116 | github.com/sivchari/tenv v1.4.7 // indirect 117 | github.com/sonatard/noctx v0.0.1 // indirect 118 | github.com/sourcegraph/go-diff v0.6.1 // indirect 119 | github.com/spf13/afero v1.6.0 // indirect 120 | github.com/spf13/cast v1.4.1 // indirect 121 | github.com/spf13/cobra v1.2.1 // indirect 122 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 123 | github.com/spf13/pflag v1.0.5 // indirect 124 | github.com/spf13/viper v1.9.0 // indirect 125 | github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect 126 | github.com/stretchr/objx v0.1.1 // indirect 127 | github.com/stretchr/testify v1.7.0 // indirect 128 | github.com/subosito/gotenv v1.2.0 // indirect 129 | github.com/sylvia7788/contextcheck v1.0.4 // indirect 130 | github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b // indirect 131 | github.com/tetafro/godot v1.4.11 // indirect 132 | github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94 // indirect 133 | github.com/tomarrell/wrapcheck/v2 v2.4.0 // indirect 134 | github.com/tommy-muehle/go-mnd/v2 v2.4.0 // indirect 135 | github.com/ultraware/funlen v0.0.3 // indirect 136 | github.com/ultraware/whitespace v0.0.4 // indirect 137 | github.com/uudashr/gocognit v1.0.5 // indirect 138 | github.com/yeya24/promlinter v0.1.0 // indirect 139 | golang.org/x/mod v0.5.0 // indirect 140 | golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect 141 | golang.org/x/text v0.3.7 // indirect 142 | golang.org/x/tools v0.1.7 // indirect 143 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 144 | google.golang.org/protobuf v1.27.1 // indirect 145 | gopkg.in/ini.v1 v1.63.2 // indirect 146 | gopkg.in/yaml.v2 v2.4.0 // indirect 147 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 148 | honnef.co/go/tools v0.2.1 // indirect 149 | mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect 150 | mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect 151 | mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7 // indirect 152 | ) 153 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /gen/aot/decimal_opt.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = 'decimal.ll' 2 | source_filename = "decimal.ll" 3 | 4 | %MyDecimal = type <{ i8, i8, i8, i1, [9 x i32] }> 5 | 6 | @div9 = internal unnamed_addr constant [128 x i64] [i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 1, i64 2, i64 2, i64 2, i64 2, i64 2, i64 2, i64 2, i64 2, i64 2, i64 3, i64 3, i64 3, i64 3, i64 3, i64 3, i64 3, i64 3, i64 3, i64 4, i64 4, i64 4, i64 4, i64 4, i64 4, i64 4, i64 4, i64 4, i64 5, i64 5, i64 5, i64 5, i64 5, i64 5, i64 5, i64 5, i64 5, i64 6, i64 6, i64 6, i64 6, i64 6, i64 6, i64 6, i64 6, i64 6, i64 7, i64 7, i64 7, i64 7, i64 7, i64 7, i64 7, i64 7, i64 7, i64 8, i64 8, i64 8, i64 8, i64 8, i64 8, i64 8, i64 8, i64 8, i64 9, i64 9, i64 9, i64 9, i64 9, i64 9, i64 9, i64 9, i64 9, i64 10, i64 10, i64 10, i64 10, i64 10, i64 10, i64 10, i64 10, i64 10, i64 11, i64 11, i64 11, i64 11, i64 11, i64 11, i64 11, i64 11, i64 11, i64 12, i64 12, i64 12, i64 12, i64 12, i64 12, i64 12, i64 12, i64 12, i64 13, i64 13, i64 13, i64 13, i64 13, i64 13, i64 13, i64 13, i64 13, i64 14, i64 14], align 8 7 | 8 | ; Function Attrs: alwaysinline 9 | define internal i32 @DecimalMul(%MyDecimal* nocapture readonly dereferenceable_or_null(40) %from1, %MyDecimal* nocapture readonly dereferenceable_or_null(40) %from2, %MyDecimal* dereferenceable_or_null(40) %to) unnamed_addr #0 { 10 | entry: 11 | %0 = icmp ne %MyDecimal* %from1, null 12 | tail call void @llvm.assume(i1 %0) 13 | %1 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 0 14 | %2 = load i8, i8* %1, align 1 15 | %3 = sext i8 %2 to i64 16 | %4 = add nsw i64 %3, 8 17 | %5 = icmp ult i64 %4, 128 18 | br i1 %5, label %if.then.i, label %if.done.i 19 | 20 | if.then.i: ; preds = %entry 21 | %6 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %4 22 | %7 = load i64, i64* %6, align 8 23 | br label %digitsToWords.exit 24 | 25 | if.done.i: ; preds = %entry 26 | %.lhs.trunc97 = trunc i64 %4 to i16 27 | %8 = sdiv i16 %.lhs.trunc97, 9 28 | %.sext98 = sext i16 %8 to i64 29 | br label %digitsToWords.exit 30 | 31 | digitsToWords.exit: ; preds = %if.then.i, %if.done.i 32 | %common.ret.op.i = phi i64 [ %.sext98, %if.done.i ], [ %7, %if.then.i ] 33 | %9 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 1 34 | %10 = load i8, i8* %9, align 1 35 | %11 = sext i8 %10 to i64 36 | %12 = add nsw i64 %11, 8 37 | %13 = icmp ult i64 %12, 128 38 | br i1 %13, label %if.then.i66, label %if.done.i68 39 | 40 | if.then.i66: ; preds = %digitsToWords.exit 41 | %14 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %12 42 | %15 = load i64, i64* %14, align 8 43 | br label %digitsToWords.exit69 44 | 45 | if.done.i68: ; preds = %digitsToWords.exit 46 | %.lhs.trunc95 = trunc i64 %12 to i16 47 | %16 = sdiv i16 %.lhs.trunc95, 9 48 | %.sext96 = sext i16 %16 to i64 49 | br label %digitsToWords.exit69 50 | 51 | digitsToWords.exit69: ; preds = %if.then.i66, %if.done.i68 52 | %common.ret.op.i67 = phi i64 [ %.sext96, %if.done.i68 ], [ %15, %if.then.i66 ] 53 | %17 = icmp ne %MyDecimal* %from2, null 54 | tail call void @llvm.assume(i1 %17) 55 | %18 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 0 56 | %19 = load i8, i8* %18, align 1 57 | %20 = sext i8 %19 to i64 58 | %21 = add nsw i64 %20, 8 59 | %22 = icmp ult i64 %21, 128 60 | br i1 %22, label %if.then.i70, label %if.done.i72 61 | 62 | if.then.i70: ; preds = %digitsToWords.exit69 63 | %23 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %21 64 | %24 = load i64, i64* %23, align 8 65 | br label %digitsToWords.exit73 66 | 67 | if.done.i72: ; preds = %digitsToWords.exit69 68 | %.lhs.trunc93 = trunc i64 %21 to i16 69 | %25 = sdiv i16 %.lhs.trunc93, 9 70 | %.sext94 = sext i16 %25 to i64 71 | br label %digitsToWords.exit73 72 | 73 | digitsToWords.exit73: ; preds = %if.then.i70, %if.done.i72 74 | %common.ret.op.i71 = phi i64 [ %.sext94, %if.done.i72 ], [ %24, %if.then.i70 ] 75 | %26 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 1 76 | %27 = load i8, i8* %26, align 1 77 | %28 = sext i8 %27 to i64 78 | %29 = add nsw i64 %28, 8 79 | %30 = icmp ult i64 %29, 128 80 | br i1 %30, label %if.then.i74, label %if.done.i76 81 | 82 | if.then.i74: ; preds = %digitsToWords.exit73 83 | %31 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %29 84 | %32 = load i64, i64* %31, align 8 85 | br label %digitsToWords.exit77 86 | 87 | if.done.i76: ; preds = %digitsToWords.exit73 88 | %.lhs.trunc91 = trunc i64 %29 to i16 89 | %33 = sdiv i16 %.lhs.trunc91, 9 90 | %.sext92 = sext i16 %33 to i64 91 | br label %digitsToWords.exit77 92 | 93 | digitsToWords.exit77: ; preds = %if.then.i74, %if.done.i76 94 | %common.ret.op.i75 = phi i64 [ %.sext92, %if.done.i76 ], [ %32, %if.then.i74 ] 95 | %34 = add nsw i64 %4, %20 96 | %35 = icmp ult i64 %34, 128 97 | br i1 %35, label %if.then.i78, label %if.done.i80 98 | 99 | if.then.i78: ; preds = %digitsToWords.exit77 100 | %36 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %34 101 | %37 = load i64, i64* %36, align 8 102 | br label %digitsToWords.exit81 103 | 104 | if.done.i80: ; preds = %digitsToWords.exit77 105 | %.lhs.trunc89 = trunc i64 %34 to i16 106 | %38 = sdiv i16 %.lhs.trunc89, 9 107 | %.sext90 = sext i16 %38 to i64 108 | br label %digitsToWords.exit81 109 | 110 | digitsToWords.exit81: ; preds = %if.then.i78, %if.done.i80 111 | %common.ret.op.i79 = phi i64 [ %.sext90, %if.done.i80 ], [ %37, %if.then.i78 ] 112 | %39 = add i64 %common.ret.op.i75, %common.ret.op.i67 113 | %40 = icmp ne %MyDecimal* %to, null 114 | tail call void @llvm.assume(i1 %40) 115 | %41 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 2 116 | %42 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 2 117 | %43 = load i8, i8* %42, align 1 118 | %44 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 2 119 | %45 = load i8, i8* %44, align 1 120 | %46 = add i8 %45, %43 121 | %47 = icmp slt i8 %46, 30 122 | %spec.select.i = select i1 %47, i8 %46, i8 30 123 | store i8 %spec.select.i, i8* %41, align 1 124 | %48 = add i64 %common.ret.op.i79, %39 125 | %49 = icmp sgt i64 %48, 9 126 | br i1 %49, label %if.then.i82, label %if.done2.i 127 | 128 | if.then.i82: ; preds = %digitsToWords.exit81 129 | %50 = icmp sgt i64 %common.ret.op.i79, 9 130 | br i1 %50, label %fixWordCntError.exit, label %if.done.i84 131 | 132 | if.done.i84: ; preds = %if.then.i82 133 | %51 = sub i64 9, %common.ret.op.i79 134 | %52 = insertvalue { i64, i64, i32 } zeroinitializer, i64 %common.ret.op.i79, 0 135 | %53 = insertvalue { i64, i64, i32 } %52, i64 %51, 1 136 | %54 = insertvalue { i64, i64, i32 } %53, i32 2, 2 137 | br label %fixWordCntError.exit 138 | 139 | if.done2.i: ; preds = %digitsToWords.exit81 140 | %55 = insertvalue { i64, i64, i32 } zeroinitializer, i64 %common.ret.op.i79, 0 141 | %56 = insertvalue { i64, i64, i32 } %55, i64 %39, 1 142 | %57 = insertvalue { i64, i64, i32 } %56, i32 0, 2 143 | br label %fixWordCntError.exit 144 | 145 | fixWordCntError.exit: ; preds = %if.then.i82, %if.done.i84, %if.done2.i 146 | %common.ret.op.i83 = phi { i64, i64, i32 } [ %54, %if.done.i84 ], [ %57, %if.done2.i ], [ { i64 9, i64 0, i32 1 }, %if.then.i82 ] 147 | %58 = extractvalue { i64, i64, i32 } %common.ret.op.i83, 0 148 | %59 = extractvalue { i64, i64, i32 } %common.ret.op.i83, 1 149 | %60 = extractvalue { i64, i64, i32 } %common.ret.op.i83, 2 150 | %61 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 3 151 | %62 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 3 152 | %63 = load i1, i1* %62, align 1 153 | %64 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 3 154 | %65 = load i1, i1* %64, align 1 155 | %66 = xor i1 %63, %65 156 | store i1 %66, i1* %61, align 1 157 | %67 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 1 158 | %68 = load i8, i8* %9, align 1 159 | %69 = load i8, i8* %26, align 1 160 | %70 = add i8 %69, %68 161 | %71 = icmp slt i8 %70, 31 162 | %spec.store.select = select i1 %71, i8 %70, i8 31 163 | store i8 %spec.store.select, i8* %67, align 1 164 | %72 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 0 165 | %73 = trunc i64 %58 to i8 166 | %74 = mul i8 %73, 9 167 | store i8 %74, i8* %72, align 1 168 | switch i32 %60, label %deref.next105 [ 169 | i32 1, label %if.then1 170 | i32 0, label %if.done11 171 | ] 172 | 173 | if.then1: ; preds = %if.then14, %for.body19, %gep.next207, %digitsToWords.exit88, %fixWordCntError.exit, %for.done31 174 | %merge = phi i32 [ %60, %fixWordCntError.exit ], [ %60, %for.done31 ], [ %60, %digitsToWords.exit88 ], [ %60, %gep.next207 ], [ 1, %for.body19 ], [ 1, %if.then14 ] 175 | ret i32 %merge 176 | 177 | if.done7: ; preds = %deref.next105, %store.next109 178 | %75 = icmp sgt i64 %common.ret.op.i79, %58 179 | br i1 %75, label %if.then8, label %if.else 180 | 181 | if.then8: ; preds = %if.done7 182 | %76 = sub i64 %common.ret.op.i79, %58 183 | %77 = ashr i64 %76, 1 184 | %.neg65 = sub i64 %common.ret.op.i71, %76 185 | %78 = add i64 %.neg65, %77 186 | br label %if.done11 187 | 188 | if.else: ; preds = %if.done7 189 | %79 = sub i64 %39, %59 190 | %80 = ashr i64 %79, 1 191 | %.not62 = icmp sgt i64 %common.ret.op.i67, %common.ret.op.i75 192 | br i1 %.not62, label %if.else10, label %if.then9 193 | 194 | if.then9: ; preds = %if.else 195 | %81 = sub i64 %common.ret.op.i67, %80 196 | %.neg64 = sub i64 %common.ret.op.i75, %79 197 | %82 = add i64 %.neg64, %80 198 | br label %if.done11 199 | 200 | if.else10: ; preds = %if.else 201 | %83 = sub i64 %common.ret.op.i75, %80 202 | %.neg63 = sub i64 %common.ret.op.i67, %79 203 | %84 = add i64 %.neg63, %80 204 | br label %if.done11 205 | 206 | if.done11: ; preds = %fixWordCntError.exit, %if.else10, %if.then9, %if.then8 207 | %85 = phi i64 [ 0, %if.then8 ], [ %81, %if.then9 ], [ %84, %if.else10 ], [ %common.ret.op.i67, %fixWordCntError.exit ] 208 | %86 = phi i64 [ %78, %if.then8 ], [ %common.ret.op.i71, %if.then9 ], [ %common.ret.op.i71, %if.else10 ], [ %common.ret.op.i71, %fixWordCntError.exit ] 209 | %87 = phi i64 [ 0, %if.then8 ], [ %82, %if.then9 ], [ %83, %if.else10 ], [ %common.ret.op.i75, %fixWordCntError.exit ] 210 | %88 = add i64 %58, %59 211 | %89 = add i64 %87, %common.ret.op.i71 212 | %90 = sub i64 %common.ret.op.i71, %86 213 | %.repack = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 0 214 | %91 = add i64 %common.ret.op.i, -1 215 | %92 = add i64 %91, %85 216 | %93 = add i64 %89, -1 217 | %.not59106 = icmp slt i64 %93, %90 218 | %94 = icmp sgt i64 %92, -1 219 | %95 = bitcast i32* %.repack to i8* 220 | call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 4 dereferenceable(36) %95, i8 0, i64 36, i1 false) 221 | br i1 %94, label %for.loop12.preheader, label %deref.next171 222 | 223 | for.loop12.preheader: ; preds = %if.done11, %for.done22 224 | %.in = phi i64 [ %97, %for.done22 ], [ %88, %if.done11 ] 225 | %96 = phi i64 [ %105, %for.done22 ], [ %92, %if.done11 ] 226 | %97 = add i64 %.in, -1 227 | %98 = icmp ult i64 %96, 9 228 | %99 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 %96 229 | br i1 %.not59106, label %for.done22, label %gep.next123.lr.ph 230 | 231 | gep.next123.lr.ph: ; preds = %for.loop12.preheader 232 | tail call void @llvm.assume(i1 %98) 233 | br label %gep.next123 234 | 235 | for.done: ; preds = %gep.next123 236 | %100 = icmp sgt i32 %158, 0 237 | br i1 %100, label %if.then14, label %for.done22 238 | 239 | if.then14: ; preds = %for.done 240 | %101 = icmp eq i64 %127, 0 241 | br i1 %101, label %if.then1, label %gep.next147 242 | 243 | for.body19: ; preds = %for.body19.preheader, %gep.next159 244 | %.in112 = phi i64 [ %103, %gep.next159 ], [ %159, %for.body19.preheader ] 245 | %102 = phi i32 [ 1, %gep.next159 ], [ %.mux, %for.body19.preheader ] 246 | %103 = add nsw i64 %.in112, -1 247 | %104 = icmp slt i64 %.in112, 1 248 | br i1 %104, label %if.then1, label %gep.next159 249 | 250 | for.done22: ; preds = %gep.next159, %gep.next147, %for.loop12.preheader, %for.done 251 | %105 = add i64 %96, -1 252 | %106 = icmp sgt i64 %105, -1 253 | br i1 %106, label %for.loop12.preheader, label %deref.next171.loopexit 254 | 255 | for.body25: ; preds = %for.body25.preheader, %if.done26 256 | %107 = phi i64 [ %111, %if.done26 ], [ 0, %for.body25.preheader ] 257 | %108 = icmp ult i64 %107, 9 258 | tail call void @llvm.assume(i1 %108) 259 | %109 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %107 260 | %110 = load i32, i32* %109, align 4 261 | %.not34 = icmp eq i32 %110, 0 262 | br i1 %.not34, label %if.done26, label %deref.next187 263 | 264 | if.done26: ; preds = %for.body25 265 | %111 = add nuw nsw i64 %107, 1 266 | %112 = icmp eq i64 %111, %88 267 | br i1 %112, label %deref.next181, label %for.body25 268 | 269 | for.body30: ; preds = %deref.next197 270 | %113 = add nuw nsw i64 %194, 1 271 | %114 = add nsw i8 %192, -9 272 | store i8 %114, i8* %72, align 1 273 | %115 = add i64 %193, -1 274 | %116 = icmp ult i64 %194, 8 275 | tail call void @llvm.assume(i1 %116) 276 | %117 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %113 277 | %118 = load i32, i32* %117, align 4 278 | %119 = icmp eq i32 %118, 0 279 | br i1 %119, label %deref.next197, label %for.done31 280 | 281 | for.done31: ; preds = %for.body30, %deref.next197 282 | %.lcssa103 = phi i64 [ %113, %for.body30 ], [ %194, %deref.next197 ] 283 | %.lcssa = phi i64 [ %115, %for.body30 ], [ %193, %deref.next197 ] 284 | %.not = icmp ne i64 %.lcssa103, 0 285 | %120 = icmp sgt i64 %.lcssa, 0 286 | %or.cond = select i1 %.not, i1 %120, i1 false 287 | br i1 %or.cond, label %gep.next207.preheader, label %if.then1 288 | 289 | gep.next207.preheader: ; preds = %for.done31 290 | %121 = insertelement <2 x i64> , i64 %.lcssa103, i32 1 291 | br label %gep.next207 292 | 293 | deref.next105: ; preds = %fixWordCntError.exit 294 | %122 = trunc i64 %59 to i8 295 | %123 = mul i8 %122, 9 296 | %124 = icmp sgt i8 %spec.store.select, %123 297 | br i1 %124, label %store.next109, label %if.done7 298 | 299 | store.next109: ; preds = %deref.next105 300 | store i8 %123, i8* %67, align 1 301 | br label %if.done7 302 | 303 | gep.next123: ; preds = %gep.next123.lr.ph, %gep.next123 304 | %125 = phi i64 [ %93, %gep.next123.lr.ph ], [ %160, %gep.next123 ] 305 | %126 = phi i32 [ 0, %gep.next123.lr.ph ], [ %158, %gep.next123 ] 306 | %127 = phi i64 [ %97, %gep.next123.lr.ph ], [ %159, %gep.next123 ] 307 | %128 = load i32, i32* %99, align 4 308 | %129 = sext i32 %128 to i64 309 | %130 = icmp ult i64 %125, 9 310 | tail call void @llvm.assume(i1 %130) 311 | %131 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 %125 312 | %132 = load i32, i32* %131, align 4 313 | %133 = sext i32 %132 to i64 314 | %134 = mul nsw i64 %133, %129 315 | %135 = sdiv i64 %134, 1000000000 316 | %136 = trunc i64 %135 to i32 317 | %137 = and i64 %135, 4294967295 318 | %.neg = mul nsw i64 %137, -1000000000 319 | %138 = add nsw i64 %.neg, %134 320 | %139 = icmp ult i64 %127, 9 321 | tail call void @llvm.assume(i1 %139) 322 | %140 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %127 323 | %141 = load i32, i32* %140, align 4 324 | %142 = sext i32 %141 to i64 325 | %143 = shl i64 %138, 32 326 | %144 = ashr exact i64 %143, 32 327 | %145 = sext i32 %126 to i64 328 | %146 = add nsw i64 %142, %145 329 | %147 = add nsw i64 %146, %144 330 | %148 = icmp sgt i64 %147, 999999999 331 | %149 = add nsw i64 %147, -1000000000 332 | %150 = zext i1 %148 to i32 333 | %151 = select i1 %148, i64 %149, i64 %147 334 | %152 = icmp sgt i64 %151, 999999999 335 | %153 = add nsw i64 %151, 3294967296 336 | %154 = select i1 %148, i32 2, i32 1 337 | %155 = select i1 %152, i32 %154, i32 %150 338 | %156 = select i1 %152, i64 %153, i64 %151 339 | %157 = trunc i64 %156 to i32 340 | store i32 %157, i32* %140, align 4 341 | %158 = add i32 %155, %136 342 | %159 = add nsw i64 %127, -1 343 | %160 = add nsw i64 %125, -1 344 | %.not59.not = icmp sgt i64 %125, %90 345 | br i1 %.not59.not, label %gep.next123, label %for.done 346 | 347 | gep.next147: ; preds = %if.then14 348 | %161 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %159 349 | %162 = load i32, i32* %161, align 4 350 | %163 = sext i32 %162 to i64 351 | %164 = zext i32 %158 to i64 352 | %165 = add nsw i64 %163, %164 353 | %166 = icmp sgt i64 %165, 999999999 354 | %167 = add nsw i64 %165, -1000000000 355 | %168 = select i1 %166, i64 %167, i64 %165 356 | %169 = icmp sgt i64 %168, 999999999 357 | %170 = add nsw i64 %168, 3294967296 358 | %171 = select i1 %169, i64 %170, i64 %168 359 | %172 = trunc i64 %171 to i32 360 | store i32 %172, i32* %161, align 4 361 | %brmerge = or i1 %169, %166 362 | br i1 %brmerge, label %for.body19.preheader, label %for.done22 363 | 364 | for.body19.preheader: ; preds = %gep.next147 365 | %173 = and i1 %169, %166 366 | %.mux = select i1 %173, i32 2, i32 1 367 | br label %for.body19 368 | 369 | gep.next159: ; preds = %for.body19 370 | %174 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %103 371 | %175 = load i32, i32* %174, align 4 372 | %176 = add i32 %175, %102 373 | %177 = icmp sgt i32 %176, 999999999 374 | %178 = add i32 %176, -1000000000 375 | %179 = select i1 %177, i32 %178, i32 %176 376 | store i32 %179, i32* %174, align 4 377 | br i1 %177, label %for.body19, label %for.done22 378 | 379 | deref.next171.loopexit: ; preds = %for.done22 380 | %.pre = load i1, i1* %61, align 1 381 | br i1 %.pre, label %for.body25.preheader, label %deref.next187 382 | 383 | deref.next171: ; preds = %if.done11 384 | br i1 %66, label %for.body25.preheader, label %deref.next187 385 | 386 | for.body25.preheader: ; preds = %deref.next171.loopexit, %deref.next171 387 | br label %for.body25 388 | 389 | deref.next181: ; preds = %if.done26 390 | %180 = load i8, i8* %41, align 1 391 | store i8 0, i8* %72, align 4 392 | store i8 %180, i8* %67, align 1 393 | %181 = bitcast i1* %61 to i8* 394 | call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(37) %181, i8 0, i64 37, i1 false) 395 | br label %deref.next187 396 | 397 | deref.next187: ; preds = %for.body25, %deref.next171.loopexit, %deref.next181, %deref.next171 398 | %182 = load i8, i8* %67, align 1 399 | %183 = sext i8 %182 to i64 400 | %184 = add nsw i64 %183, 8 401 | %185 = icmp ult i64 %184, 128 402 | br i1 %185, label %if.then.i85, label %if.done.i87 403 | 404 | if.then.i85: ; preds = %deref.next187 405 | %186 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %184 406 | %187 = load i64, i64* %186, align 8 407 | br label %digitsToWords.exit88 408 | 409 | if.done.i87: ; preds = %deref.next187 410 | %.lhs.trunc = trunc i64 %184 to i16 411 | %188 = sdiv i16 %.lhs.trunc, 9 412 | %.sext = sext i16 %188 to i64 413 | br label %digitsToWords.exit88 414 | 415 | digitsToWords.exit88: ; preds = %if.then.i85, %if.done.i87 416 | %common.ret.op.i86 = phi i64 [ %.sext, %if.done.i87 ], [ %187, %if.then.i85 ] 417 | %189 = load i32, i32* %.repack, align 4 418 | %190 = icmp eq i32 %189, 0 419 | br i1 %190, label %deref.next197.preheader, label %if.then1 420 | 421 | deref.next197.preheader: ; preds = %digitsToWords.exit88 422 | %191 = add i64 %common.ret.op.i86, %58 423 | %.pre119 = load i8, i8* %72, align 1 424 | br label %deref.next197 425 | 426 | deref.next197: ; preds = %deref.next197.preheader, %for.body30 427 | %192 = phi i8 [ %114, %for.body30 ], [ %.pre119, %deref.next197.preheader ] 428 | %193 = phi i64 [ %115, %for.body30 ], [ %191, %deref.next197.preheader ] 429 | %194 = phi i64 [ %113, %for.body30 ], [ 0, %deref.next197.preheader ] 430 | %195 = icmp sgt i8 %192, 9 431 | br i1 %195, label %for.body30, label %for.done31 432 | 433 | gep.next207: ; preds = %gep.next207.preheader, %gep.next207 434 | %196 = phi i64 [ %206, %gep.next207 ], [ %.lcssa, %gep.next207.preheader ] 435 | %197 = phi <2 x i64> [ %205, %gep.next207 ], [ %121, %gep.next207.preheader ] 436 | %198 = extractelement <2 x i64> %197, i32 0 437 | %199 = icmp ult i64 %198, 9 438 | tail call void @llvm.assume(i1 %199) 439 | %200 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %198 440 | %201 = extractelement <2 x i64> %197, i32 1 441 | %202 = icmp ult i64 %201, 9 442 | tail call void @llvm.assume(i1 %202) 443 | %203 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %201 444 | %204 = load i32, i32* %203, align 4 445 | store i32 %204, i32* %200, align 4 446 | %205 = add nuw nsw <2 x i64> %197, 447 | %206 = add nsw i64 %196, -1 448 | %207 = icmp sgt i64 %196, 1 449 | br i1 %207, label %gep.next207, label %if.then1 450 | } 451 | 452 | ; Function Attrs: alwaysinline 453 | define internal i32 @DecimalSub(%MyDecimal* dereferenceable_or_null(40) %from1, %MyDecimal* dereferenceable_or_null(40) %from2, %MyDecimal* dereferenceable_or_null(40) %to) unnamed_addr #0 { 454 | entry: 455 | %0 = icmp ne %MyDecimal* %to, null 456 | tail call void @llvm.assume(i1 %0) #3 457 | %1 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 0 458 | tail call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(40) %1, i8 0, i64 40, i1 false) #3 459 | %2 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 2 460 | %3 = icmp ne %MyDecimal* %from1, null 461 | tail call void @llvm.assume(i1 %3) 462 | %4 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 2 463 | %5 = load i8, i8* %4, align 1 464 | %6 = icmp ne %MyDecimal* %from2, null 465 | tail call void @llvm.assume(i1 %6) 466 | %7 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 2 467 | %8 = load i8, i8* %7, align 1 468 | %9 = icmp sgt i8 %5, %8 469 | %spec.select.i = select i1 %9, i8 %5, i8 %8 470 | store i8 %spec.select.i, i8* %2, align 1 471 | %10 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 3 472 | %11 = load i1, i1* %10, align 1 473 | %12 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 3 474 | %13 = load i1, i1* %12, align 1 475 | %14 = xor i1 %11, %13 476 | %15 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 0 477 | %16 = load i8, i8* %15, align 1 478 | %17 = sext i8 %16 to i64 479 | %18 = add nsw i64 %17, 8 480 | %19 = icmp ult i64 %18, 128 481 | br i1 %14, label %if.done, label %if.then 482 | 483 | common.ret: ; preds = %if.then25.i, %for.done24.i, %if.then3.i, %doSub.exit 484 | %common.ret.op = phi i32 [ %oldret1.i, %doSub.exit ], [ 1, %if.then3.i ], [ %299, %for.done24.i ], [ %299, %if.then25.i ] 485 | ret i32 %common.ret.op 486 | 487 | if.then: ; preds = %entry 488 | br i1 %19, label %if.then.i.i, label %if.done.i.i 489 | 490 | if.then.i.i: ; preds = %if.then 491 | %20 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %18 492 | %21 = load i64, i64* %20, align 8 493 | br label %digitsToWords.exit.i 494 | 495 | if.done.i.i: ; preds = %if.then 496 | %.lhs.trunc50.i = trunc i64 %18 to i16 497 | %22 = sdiv i16 %.lhs.trunc50.i, 9 498 | %.sext51.i = sext i16 %22 to i64 499 | br label %digitsToWords.exit.i 500 | 501 | digitsToWords.exit.i: ; preds = %if.done.i.i, %if.then.i.i 502 | %common.ret.op.i.i = phi i64 [ %.sext51.i, %if.done.i.i ], [ %21, %if.then.i.i ] 503 | %23 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 1 504 | %24 = load i8, i8* %23, align 1 505 | %25 = sext i8 %24 to i64 506 | %26 = add nsw i64 %25, 8 507 | %27 = icmp ult i64 %26, 128 508 | br i1 %27, label %if.then.i29.i, label %if.done.i31.i 509 | 510 | if.then.i29.i: ; preds = %digitsToWords.exit.i 511 | %28 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %26 512 | %29 = load i64, i64* %28, align 8 513 | br label %digitsToWords.exit32.i 514 | 515 | if.done.i31.i: ; preds = %digitsToWords.exit.i 516 | %.lhs.trunc48.i = trunc i64 %26 to i16 517 | %30 = sdiv i16 %.lhs.trunc48.i, 9 518 | %.sext49.i = sext i16 %30 to i64 519 | br label %digitsToWords.exit32.i 520 | 521 | digitsToWords.exit32.i: ; preds = %if.done.i31.i, %if.then.i29.i 522 | %common.ret.op.i30.i = phi i64 [ %.sext49.i, %if.done.i31.i ], [ %29, %if.then.i29.i ] 523 | %31 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 0 524 | %32 = load i8, i8* %31, align 1 525 | %33 = sext i8 %32 to i64 526 | %34 = add nsw i64 %33, 8 527 | %35 = icmp ult i64 %34, 128 528 | br i1 %35, label %if.then.i33.i, label %if.done.i35.i 529 | 530 | if.then.i33.i: ; preds = %digitsToWords.exit32.i 531 | %36 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %34 532 | %37 = load i64, i64* %36, align 8 533 | br label %digitsToWords.exit36.i 534 | 535 | if.done.i35.i: ; preds = %digitsToWords.exit32.i 536 | %.lhs.trunc46.i = trunc i64 %34 to i16 537 | %38 = sdiv i16 %.lhs.trunc46.i, 9 538 | %.sext47.i = sext i16 %38 to i64 539 | br label %digitsToWords.exit36.i 540 | 541 | digitsToWords.exit36.i: ; preds = %if.done.i35.i, %if.then.i33.i 542 | %common.ret.op.i34.i = phi i64 [ %.sext47.i, %if.done.i35.i ], [ %37, %if.then.i33.i ] 543 | %39 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 1 544 | %40 = load i8, i8* %39, align 1 545 | %41 = sext i8 %40 to i64 546 | %42 = add nsw i64 %41, 8 547 | %43 = icmp ult i64 %42, 128 548 | br i1 %43, label %if.then.i37.i, label %if.done.i39.i 549 | 550 | if.then.i37.i: ; preds = %digitsToWords.exit36.i 551 | %44 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %42 552 | %45 = load i64, i64* %44, align 8 553 | br label %digitsToWords.exit40.i 554 | 555 | if.done.i39.i: ; preds = %digitsToWords.exit36.i 556 | %.lhs.trunc.i = trunc i64 %42 to i16 557 | %46 = sdiv i16 %.lhs.trunc.i, 9 558 | %.sext.i = sext i16 %46 to i64 559 | br label %digitsToWords.exit40.i 560 | 561 | digitsToWords.exit40.i: ; preds = %if.done.i39.i, %if.then.i37.i 562 | %common.ret.op.i38.i = phi i64 [ %.sext.i, %if.done.i39.i ], [ %45, %if.then.i37.i ] 563 | %47 = icmp sgt i64 %common.ret.op.i30.i, %common.ret.op.i38.i 564 | %spec.select.i.i = select i1 %47, i64 %common.ret.op.i30.i, i64 %common.ret.op.i38.i 565 | %48 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 0 566 | %49 = load i32, i32* %48, align 4 567 | %50 = icmp eq i32 %49, 0 568 | br i1 %50, label %for.loop.preheader.i, label %gep.next87.i 569 | 570 | for.loop.preheader.i: ; preds = %digitsToWords.exit40.i 571 | %51 = icmp sgt i64 %common.ret.op.i.i, 0 572 | br i1 %51, label %for.body.i, label %for.done.i 573 | 574 | for.body.i: ; preds = %for.loop.preheader.i, %for.body.gep.next85_crit_edge.i 575 | %52 = phi i64 [ %53, %for.body.gep.next85_crit_edge.i ], [ 0, %for.loop.preheader.i ] 576 | %53 = add nuw nsw i64 %52, 1 577 | %54 = icmp sgt i64 %common.ret.op.i.i, %53 578 | br i1 %54, label %for.body.gep.next85_crit_edge.i, label %for.done.i 579 | 580 | for.body.gep.next85_crit_edge.i: ; preds = %for.body.i 581 | %.phi.trans.insert.i = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 %53 582 | %.pre.i = load i32, i32* %.phi.trans.insert.i, align 4 583 | %55 = icmp ult i64 %52, 8 584 | tail call void @llvm.assume(i1 %55) #3 585 | %56 = icmp eq i32 %.pre.i, 0 586 | br i1 %56, label %for.body.i, label %for.done.i 587 | 588 | for.done.i: ; preds = %for.body.gep.next85_crit_edge.i, %for.body.i, %for.loop.preheader.i 589 | %.lcssa77.i = phi i64 [ 0, %for.loop.preheader.i ], [ %common.ret.op.i.i, %for.body.i ], [ %53, %for.body.gep.next85_crit_edge.i ] 590 | %57 = sub i64 %common.ret.op.i.i, %.lcssa77.i 591 | br label %gep.next87.i 592 | 593 | for.body3.i: ; preds = %for.loop1.preheader.i, %for.body3.gep.next93_crit_edge.i 594 | %58 = phi i64 [ %59, %for.body3.gep.next93_crit_edge.i ], [ 0, %for.loop1.preheader.i ] 595 | %59 = add nuw nsw i64 %58, 1 596 | %60 = icmp sgt i64 %common.ret.op.i34.i, %59 597 | br i1 %60, label %for.body3.gep.next93_crit_edge.i, label %for.done4.i 598 | 599 | for.body3.gep.next93_crit_edge.i: ; preds = %for.body3.i 600 | %.phi.trans.insert125.i = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 %59 601 | %.pre126.i = load i32, i32* %.phi.trans.insert125.i, align 4 602 | %61 = icmp ult i64 %58, 8 603 | tail call void @llvm.assume(i1 %61) #3 604 | %62 = icmp eq i32 %.pre126.i, 0 605 | br i1 %62, label %for.body3.i, label %for.done4.i 606 | 607 | for.done4.i: ; preds = %for.body3.gep.next93_crit_edge.i, %for.body3.i, %for.loop1.preheader.i 608 | %.lcssa76.i = phi i64 [ 0, %for.loop1.preheader.i ], [ %common.ret.op.i34.i, %for.body3.i ], [ %59, %for.body3.gep.next93_crit_edge.i ] 609 | %63 = sub i64 %common.ret.op.i34.i, %.lcssa76.i 610 | br label %if.done5.i 611 | 612 | if.done5.i: ; preds = %gep.next87.i, %for.done4.i 613 | %64 = phi i64 [ %common.ret.op.i34.i, %gep.next87.i ], [ %63, %for.done4.i ] 614 | %65 = phi i64 [ 0, %gep.next87.i ], [ %.lcssa76.i, %for.done4.i ] 615 | %66 = icmp sgt i64 %64, %216 616 | br i1 %66, label %deref.next111.i, label %if.else43.i 617 | 618 | if.done12.i: ; preds = %if.else43.i, %gep.next261.i, %if.then57.i, %deref.next111.i 619 | %storemerge.i = phi i1 [ %222, %deref.next111.i ], [ %11, %if.then57.i ], [ %11, %gep.next261.i ], [ %11, %if.else43.i ] 620 | %67 = phi %MyDecimal* [ %from2, %deref.next111.i ], [ %from1, %if.then57.i ], [ %from1, %gep.next261.i ], [ %from1, %if.else43.i ] 621 | %68 = phi %MyDecimal* [ %from1, %deref.next111.i ], [ %from2, %if.then57.i ], [ %from2, %gep.next261.i ], [ %from2, %if.else43.i ] 622 | %69 = phi i64 [ %64, %deref.next111.i ], [ %216, %if.then57.i ], [ %216, %gep.next261.i ], [ %216, %if.else43.i ] 623 | %70 = phi i64 [ %.ph20, %deref.next111.i ], [ %205, %if.then57.i ], [ %205, %gep.next261.i ], [ %common.ret.op.i30.i, %if.else43.i ] 624 | %71 = phi i64 [ %65, %deref.next111.i ], [ %217, %if.then57.i ], [ %217, %gep.next261.i ], [ %217, %if.else43.i ] 625 | %72 = phi i64 [ %217, %deref.next111.i ], [ %65, %if.then57.i ], [ %65, %gep.next261.i ], [ %65, %if.else43.i ] 626 | %73 = phi <2 x i64> [ %224, %deref.next111.i ], [ %215, %if.then57.i ], [ %251, %gep.next261.i ], [ %199, %if.else43.i ] 627 | %74 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 3 628 | store i1 %storemerge.i, i1* %74, align 1 629 | %75 = add i64 %69, %spec.select.i.i 630 | %76 = icmp sgt i64 %75, 9 631 | br i1 %76, label %if.then.i41.i, label %if.done2.i.i 632 | 633 | if.then.i41.i: ; preds = %if.done12.i 634 | %77 = icmp sgt i64 %69, 9 635 | br i1 %77, label %fixWordCntError.exit.i, label %if.done.i43.i 636 | 637 | if.done.i43.i: ; preds = %if.then.i41.i 638 | %78 = sub i64 9, %69 639 | %79 = insertvalue { i64, i64, i32 } zeroinitializer, i64 %69, 0 640 | %80 = insertvalue { i64, i64, i32 } %79, i64 %78, 1 641 | %81 = insertvalue { i64, i64, i32 } %80, i32 2, 2 642 | br label %fixWordCntError.exit.i 643 | 644 | if.done2.i.i: ; preds = %if.done12.i 645 | %82 = insertvalue { i64, i64, i32 } zeroinitializer, i64 %69, 0 646 | %83 = insertvalue { i64, i64, i32 } %82, i64 %spec.select.i.i, 1 647 | %84 = insertvalue { i64, i64, i32 } %83, i32 0, 2 648 | br label %fixWordCntError.exit.i 649 | 650 | fixWordCntError.exit.i: ; preds = %if.done2.i.i, %if.done.i43.i, %if.then.i41.i 651 | %common.ret.op.i42.i = phi { i64, i64, i32 } [ %81, %if.done.i43.i ], [ %84, %if.done2.i.i ], [ { i64 9, i64 0, i32 1 }, %if.then.i41.i ] 652 | %85 = extractvalue { i64, i64, i32 } %common.ret.op.i42.i, 0 653 | %86 = extractvalue { i64, i64, i32 } %common.ret.op.i42.i, 1 654 | %87 = extractvalue { i64, i64, i32 } %common.ret.op.i42.i, 2 655 | %88 = add i64 %85, %86 656 | %89 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 1 657 | %90 = getelementptr inbounds %MyDecimal, %MyDecimal* %67, i64 0, i32 1 658 | %91 = load i8, i8* %90, align 1 659 | store i8 %91, i8* %89, align 1 660 | %92 = getelementptr inbounds %MyDecimal, %MyDecimal* %68, i64 0, i32 1 661 | %93 = load i8, i8* %92, align 1 662 | %94 = icmp slt i8 %91, %93 663 | %spec.store.select.i = select i1 %94, i8 %93, i8 %91 664 | store i8 %spec.store.select.i, i8* %89, align 1 665 | %95 = trunc i64 %85 to i8 666 | %96 = mul i8 %95, 9 667 | store i8 %96, i8* %1, align 1 668 | %.not.i = icmp eq i32 %87, 0 669 | br i1 %.not.i, label %if.done23.i, label %deref.next145.i 670 | 671 | if.done17.i: ; preds = %store.next149.i, %deref.next145.i 672 | %97 = icmp sgt i64 %70, %86 673 | %spec.select.i1 = select i1 %97, i64 %86, i64 %70 674 | %98 = insertelement <2 x i64> poison, i64 %85, i32 0 675 | %99 = insertelement <2 x i64> %98, i64 %86, i32 1 676 | %100 = icmp sgt <2 x i64> %73, %99 677 | %101 = select <2 x i1> %100, <2 x i64> %99, <2 x i64> %73 678 | br label %if.done23.i 679 | 680 | if.done23.i: ; preds = %if.done17.i, %fixWordCntError.exit.i 681 | %102 = phi i64 [ %70, %fixWordCntError.exit.i ], [ %spec.select.i1, %if.done17.i ] 682 | %103 = phi <2 x i64> [ %73, %fixWordCntError.exit.i ], [ %101, %if.done17.i ] 683 | %104 = extractelement <2 x i64> %103, i32 1 684 | %105 = icmp sgt i64 %102, %104 685 | %106 = add i64 %85, %71 686 | %107 = add i64 %102, %106 687 | br i1 %105, label %if.then24.i, label %if.else.i 688 | 689 | if.then24.i: ; preds = %if.done23.i 690 | %108 = add i64 %104, %106 691 | %109 = extractelement <2 x i64> %103, i32 0 692 | %110 = add i64 %109, %72 693 | %111 = add i64 %110, %104 694 | %112 = icmp sgt i64 %86, %102 695 | br i1 %112, label %for.body26.preheader.i, label %for.loop27.preheader.i 696 | 697 | for.body26.preheader.i: ; preds = %if.then24.i 698 | %113 = add i64 %102, %85 699 | %114 = shl i64 %113, 2 700 | %115 = add i64 %114, 4 701 | %uglygep119.i = getelementptr i8, i8* %1, i64 %115 702 | %116 = sub i64 %86, %102 703 | %117 = shl i64 %116, 2 704 | tail call void @llvm.memset.p0i8.i64(i8* align 4 %uglygep119.i, i8 0, i64 %117, i1 false) #3 705 | br label %for.loop27.preheader.i 706 | 707 | for.loop27.preheader.i: ; preds = %for.body26.preheader.i, %if.then24.i 708 | %.lcssa65.i = phi i64 [ %88, %if.then24.i ], [ %113, %for.body26.preheader.i ] 709 | %118 = icmp sgt i64 %107, %108 710 | br i1 %118, label %for.body28.i, label %for.loop29.preheader.i 711 | 712 | for.body28.i: ; preds = %for.loop27.preheader.i, %for.body28.i 713 | %119 = phi i64 [ %121, %for.body28.i ], [ %.lcssa65.i, %for.loop27.preheader.i ] 714 | %120 = phi i64 [ %122, %for.body28.i ], [ %107, %for.loop27.preheader.i ] 715 | %121 = add nsw i64 %119, -1 716 | %122 = add nsw i64 %120, -1 717 | %123 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %121 718 | %124 = getelementptr inbounds %MyDecimal, %MyDecimal* %67, i64 0, i32 4, i64 %122 719 | %125 = load i32, i32* %124, align 4 720 | store i32 %125, i32* %123, align 4 721 | %126 = icmp sgt i64 %122, %108 722 | br i1 %126, label %for.body28.i, label %for.loop29.preheader.i 723 | 724 | for.loop31.preheader.i: ; preds = %for.body30.i, %for.loop29.preheader.i 725 | %.lcssa62.i = phi i64 [ %.ph.i, %for.loop29.preheader.i ], [ %134, %for.body30.i ] 726 | %.lcssa61.i = phi i32 [ %.ph55.i, %for.loop29.preheader.i ], [ %.lobit.i.i, %for.body30.i ] 727 | %.lcssa60.i = phi i64 [ %.ph56.i, %for.loop29.preheader.i ], [ %133, %for.body30.i ] 728 | %127 = icmp sgt i32 %.lcssa61.i, 0 729 | %128 = icmp sgt i64 %.lcssa62.i, %71 730 | %or.cond100.i = and i1 %128, %127 731 | br i1 %or.cond100.i, label %for.body33.i, label %for.loop34.preheader.i 732 | 733 | for.body30.i: ; preds = %for.loop29.preheader.i, %for.body30.i 734 | %129 = phi i64 [ %133, %for.body30.i ], [ %.ph56.i, %for.loop29.preheader.i ] 735 | %130 = phi i32 [ %.lobit.i.i, %for.body30.i ], [ %.ph55.i, %for.loop29.preheader.i ] 736 | %131 = phi i64 [ %135, %for.body30.i ], [ %.ph54.i, %for.loop29.preheader.i ] 737 | %132 = phi i64 [ %134, %for.body30.i ], [ %.ph.i, %for.loop29.preheader.i ] 738 | %133 = add nsw i64 %129, -1 739 | %134 = add nsw i64 %132, -1 740 | %135 = add nsw i64 %131, -1 741 | %136 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %133 742 | %137 = getelementptr inbounds %MyDecimal, %MyDecimal* %67, i64 0, i32 4, i64 %134 743 | %138 = load i32, i32* %137, align 4 744 | %139 = getelementptr inbounds %MyDecimal, %MyDecimal* %68, i64 0, i32 4, i64 %135 745 | %140 = load i32, i32* %139, align 4 746 | %141 = add i32 %130, %140 747 | %142 = sub i32 %138, %141 748 | %143 = icmp slt i32 %142, 0 749 | %144 = add i32 %142, 1000000000 750 | %.lobit.i.i = lshr i32 %142, 31 751 | %145 = select i1 %143, i32 %144, i32 %142 752 | store i32 %145, i32* %136, align 4 753 | %146 = icmp sgt i64 %135, %72 754 | br i1 %146, label %for.body30.i, label %for.loop31.preheader.i 755 | 756 | for.loop34.preheader.i: ; preds = %for.body33.i, %for.loop31.preheader.i 757 | %.lcssa59.i = phi i64 [ %.lcssa62.i, %for.loop31.preheader.i ], [ %151, %for.body33.i ] 758 | %.lcssa58.i = phi i64 [ %.lcssa60.i, %for.loop31.preheader.i ], [ %150, %for.body33.i ] 759 | %147 = icmp sgt i64 %.lcssa59.i, %71 760 | br i1 %147, label %for.body35.i, label %for.loop36.preheader.i 761 | 762 | for.body33.i: ; preds = %for.loop31.preheader.i, %for.body33.i 763 | %148 = phi i64 [ %150, %for.body33.i ], [ %.lcssa60.i, %for.loop31.preheader.i ] 764 | %149 = phi i64 [ %151, %for.body33.i ], [ %.lcssa62.i, %for.loop31.preheader.i ] 765 | %150 = add nsw i64 %148, -1 766 | %151 = add nsw i64 %149, -1 767 | %152 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %150 768 | %153 = getelementptr inbounds %MyDecimal, %MyDecimal* %67, i64 0, i32 4, i64 %151 769 | %154 = load i32, i32* %153, align 4 770 | %155 = add i32 %154, -1 771 | %156 = icmp slt i32 %155, 0 772 | %157 = add i32 %154, 999999999 773 | %158 = select i1 %156, i32 %157, i32 %155 774 | store i32 %158, i32* %152, align 4 775 | %159 = icmp sgt i64 %151, %71 776 | %or.cond.i = and i1 %159, %156 777 | br i1 %or.cond.i, label %for.body33.i, label %for.loop34.preheader.i 778 | 779 | for.loop36.preheader.i: ; preds = %for.body35.i, %for.loop34.preheader.i 780 | %.lcssa.i = phi i64 [ %.lcssa58.i, %for.loop34.preheader.i ], [ %164, %for.body35.i ] 781 | %160 = icmp sgt i64 %.lcssa.i, 0 782 | br i1 %160, label %for.body37.preheader.i, label %for.done38.i 783 | 784 | for.body37.preheader.i: ; preds = %for.loop36.preheader.i 785 | %scevgep.i = getelementptr %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 0 786 | %scevgep124.i = bitcast i32* %scevgep.i to i8* 787 | %161 = shl nuw i64 %.lcssa.i, 2 788 | tail call void @llvm.memset.p0i8.i64(i8* align 4 %scevgep124.i, i8 0, i64 %161, i1 false) #3 789 | br label %for.done38.i 790 | 791 | for.body35.i: ; preds = %for.loop34.preheader.i, %for.body35.i 792 | %162 = phi i64 [ %164, %for.body35.i ], [ %.lcssa58.i, %for.loop34.preheader.i ] 793 | %163 = phi i64 [ %165, %for.body35.i ], [ %.lcssa59.i, %for.loop34.preheader.i ] 794 | %164 = add nsw i64 %162, -1 795 | %165 = add nsw i64 %163, -1 796 | %166 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %164 797 | %167 = getelementptr inbounds %MyDecimal, %MyDecimal* %67, i64 0, i32 4, i64 %165 798 | %168 = load i32, i32* %167, align 4 799 | store i32 %168, i32* %166, align 4 800 | %169 = icmp sgt i64 %165, %71 801 | br i1 %169, label %for.body35.i, label %for.loop36.preheader.i 802 | 803 | for.done38.i: ; preds = %for.body37.preheader.i, %for.loop36.preheader.i 804 | %170 = insertvalue { i64, i32 } zeroinitializer, i32 %87, 1 805 | br label %doSub.exit 806 | 807 | if.else.i: ; preds = %if.done23.i 808 | %171 = extractelement <2 x i64> %103, i32 0 809 | %172 = add i64 %171, %72 810 | %173 = add i64 %172, %104 811 | %174 = add i64 %172, %102 812 | %175 = icmp sgt i64 %86, %104 813 | br i1 %175, label %for.body40.preheader.i, label %for.loop41.preheader.i 814 | 815 | for.body40.preheader.i: ; preds = %if.else.i 816 | %176 = add i64 %104, %85 817 | %177 = shl i64 %176, 2 818 | %178 = add i64 %177, 4 819 | %uglygep.i = getelementptr i8, i8* %1, i64 %178 820 | %179 = sub i64 %86, %104 821 | %180 = shl i64 %179, 2 822 | tail call void @llvm.memset.p0i8.i64(i8* align 4 %uglygep.i, i8 0, i64 %180, i1 false) #3 823 | br label %for.loop41.preheader.i 824 | 825 | for.loop41.preheader.i: ; preds = %for.body40.preheader.i, %if.else.i 826 | %.lcssa69.i = phi i64 [ %88, %if.else.i ], [ %176, %for.body40.preheader.i ] 827 | %181 = icmp sgt i64 %173, %174 828 | br i1 %181, label %for.body42.i, label %for.loop29.preheader.i 829 | 830 | for.loop29.preheader.i: ; preds = %for.body42.i, %for.body28.i, %for.loop41.preheader.i, %for.loop27.preheader.i 831 | %.ph.i = phi i64 [ %107, %for.loop27.preheader.i ], [ %107, %for.loop41.preheader.i ], [ %122, %for.body28.i ], [ %107, %for.body42.i ] 832 | %.ph54.i = phi i64 [ %111, %for.loop27.preheader.i ], [ %173, %for.loop41.preheader.i ], [ %111, %for.body28.i ], [ %187, %for.body42.i ] 833 | %.ph55.i = phi i32 [ 0, %for.loop27.preheader.i ], [ 0, %for.loop41.preheader.i ], [ 0, %for.body28.i ], [ %.lobit.i45.i, %for.body42.i ] 834 | %.ph56.i = phi i64 [ %.lcssa65.i, %for.loop27.preheader.i ], [ %.lcssa69.i, %for.loop41.preheader.i ], [ %121, %for.body28.i ], [ %186, %for.body42.i ] 835 | %182 = icmp sgt i64 %.ph54.i, %72 836 | br i1 %182, label %for.body30.i, label %for.loop31.preheader.i 837 | 838 | for.body42.i: ; preds = %for.loop41.preheader.i, %for.body42.i 839 | %183 = phi i64 [ %186, %for.body42.i ], [ %.lcssa69.i, %for.loop41.preheader.i ] 840 | %184 = phi i32 [ %.lobit.i45.i, %for.body42.i ], [ 0, %for.loop41.preheader.i ] 841 | %185 = phi i64 [ %187, %for.body42.i ], [ %173, %for.loop41.preheader.i ] 842 | %186 = add nsw i64 %183, -1 843 | %187 = add nsw i64 %185, -1 844 | %188 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %186 845 | %189 = getelementptr inbounds %MyDecimal, %MyDecimal* %68, i64 0, i32 4, i64 %187 846 | %190 = load i32, i32* %189, align 4 847 | %191 = add i32 %190, %184 848 | %192 = sub i32 0, %191 849 | %193 = icmp slt i32 %192, 0 850 | %194 = sub i32 1000000000, %191 851 | %.lobit.i45.i = lshr i32 %192, 31 852 | %195 = select i1 %193, i32 %194, i32 %192 853 | store i32 %195, i32* %188, align 4 854 | %196 = icmp sgt i64 %187, %174 855 | br i1 %196, label %for.body42.i, label %for.loop29.preheader.i 856 | 857 | if.else43.i: ; preds = %if.done5.i 858 | %197 = icmp eq i64 %64, %216 859 | %198 = insertelement <2 x i64> poison, i64 %common.ret.op.i38.i, i32 1 860 | %199 = insertelement <2 x i64> %198, i64 %64, i32 0 861 | br i1 %197, label %if.then44.i, label %if.done12.i 862 | 863 | if.then44.i: ; preds = %if.else43.i 864 | %200 = add i64 %common.ret.op.i30.i, %common.ret.op.i.i 865 | %201 = add i64 %common.ret.op.i38.i, %common.ret.op.i34.i 866 | br label %for.loop45.i 867 | 868 | for.loop45.i: ; preds = %gep.next237.i, %if.then44.i 869 | %.in28.i = phi i64 [ %200, %if.then44.i ], [ %202, %gep.next237.i ] 870 | %202 = add i64 %.in28.i, -1 871 | %.not2.i = icmp sgt i64 %217, %202 872 | br i1 %.not2.i, label %for.loop48.i.preheader, label %gep.next237.i 873 | 874 | for.loop48.i.preheader: ; preds = %gep.next237.i, %for.loop45.i 875 | br label %for.loop48.i 876 | 877 | for.loop48.i: ; preds = %for.loop48.i.preheader, %gep.next243.i 878 | %.in.i = phi i64 [ %203, %gep.next243.i ], [ %201, %for.loop48.i.preheader ] 879 | %203 = add i64 %.in.i, -1 880 | %.not3.i = icmp sgt i64 %65, %203 881 | br i1 %.not3.i, label %for.done51.i, label %gep.next243.i 882 | 883 | for.done51.i: ; preds = %gep.next243.i, %for.loop48.i 884 | %204 = sub i64 %202, %common.ret.op.i.i 885 | %205 = add i64 %204, 1 886 | %206 = sub i64 %203, %common.ret.op.i34.i 887 | %207 = add i64 %206, 1 888 | %208 = icmp sle i64 %217, %202 889 | %209 = icmp sle i64 %65, %203 890 | %or.cond27781.i = and i1 %208, %209 891 | br i1 %or.cond27781.i, label %gep.next249.i, label %for.done56.i 892 | 893 | for.body55.i: ; preds = %gep.next249.i 894 | %210 = add nuw nsw i64 %237, 1 895 | %211 = add nuw nsw i64 %236, 1 896 | %212 = icmp slt i64 %237, %202 897 | %213 = icmp slt i64 %236, %203 898 | %or.cond277.i = and i1 %213, %212 899 | br i1 %or.cond277.i, label %gep.next249.i, label %for.done56.i 900 | 901 | for.done56.i: ; preds = %for.body55.i, %for.done51.i 902 | %.lcssa73.i = phi i64 [ %217, %for.done51.i ], [ %210, %for.body55.i ] 903 | %.lcssa72.i = phi i64 [ %65, %for.done51.i ], [ %211, %for.body55.i ] 904 | %.lcssa71.i = phi i1 [ %208, %for.done51.i ], [ %212, %for.body55.i ] 905 | %.lcssa70.i = phi i1 [ %209, %for.done51.i ], [ %213, %for.body55.i ] 906 | br i1 %.lcssa71.i, label %if.then57.i, label %if.else61.i 907 | 908 | if.then57.i: ; preds = %for.done56.i 909 | %214 = insertelement <2 x i64> poison, i64 %216, i32 0 910 | %215 = insertelement <2 x i64> %214, i64 %207, i32 1 911 | br i1 %.lcssa70.i, label %if.then57.i.gep.next261.i_crit_edge, label %if.done12.i 912 | 913 | if.then57.i.gep.next261.i_crit_edge: ; preds = %if.then57.i 914 | %.phi.trans.insert = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 %.lcssa72.i 915 | %.pre = load i32, i32* %.phi.trans.insert, align 4 916 | %.phi.trans.insert78 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 %.lcssa73.i 917 | %.pre79 = load i32, i32* %.phi.trans.insert78, align 4 918 | br label %gep.next261.i 919 | 920 | if.else61.i: ; preds = %for.done56.i 921 | br i1 %.lcssa70.i, label %deref.next111.i, label %gep.next271.i 922 | 923 | gep.next87.i: ; preds = %for.done.i, %digitsToWords.exit40.i 924 | %216 = phi i64 [ %common.ret.op.i.i, %digitsToWords.exit40.i ], [ %57, %for.done.i ] 925 | %217 = phi i64 [ 0, %digitsToWords.exit40.i ], [ %.lcssa77.i, %for.done.i ] 926 | %218 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 0 927 | %219 = load i32, i32* %218, align 4 928 | %220 = icmp eq i32 %219, 0 929 | br i1 %220, label %for.loop1.preheader.i, label %if.done5.i 930 | 931 | for.loop1.preheader.i: ; preds = %gep.next87.i 932 | %221 = icmp sgt i64 %common.ret.op.i34.i, 0 933 | br i1 %221, label %for.body3.i, label %for.done4.i 934 | 935 | deref.next111.i: ; preds = %if.done5.i, %gep.next261.i, %if.else61.i 936 | %.ph = phi i64 [ %205, %if.else61.i ], [ %205, %gep.next261.i ], [ %common.ret.op.i30.i, %if.done5.i ] 937 | %.ph20 = phi i64 [ %207, %if.else61.i ], [ %207, %gep.next261.i ], [ %common.ret.op.i38.i, %if.done5.i ] 938 | %222 = xor i1 %11, true 939 | %223 = insertelement <2 x i64> poison, i64 %216, i32 0 940 | %224 = insertelement <2 x i64> %223, i64 %.ph, i32 1 941 | br label %if.done12.i 942 | 943 | deref.next145.i: ; preds = %fixWordCntError.exit.i 944 | %225 = trunc i64 %86 to i8 945 | %226 = mul i8 %225, 9 946 | %227 = icmp sgt i8 %spec.store.select.i, %226 947 | br i1 %227, label %store.next149.i, label %if.done17.i 948 | 949 | store.next149.i: ; preds = %deref.next145.i 950 | store i8 %226, i8* %89, align 1 951 | br label %if.done17.i 952 | 953 | gep.next237.i: ; preds = %for.loop45.i 954 | %228 = icmp ult i64 %202, 9 955 | tail call void @llvm.assume(i1 %228) #3 956 | %229 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 %202 957 | %230 = load i32, i32* %229, align 4 958 | %231 = icmp eq i32 %230, 0 959 | br i1 %231, label %for.loop45.i, label %for.loop48.i.preheader 960 | 961 | gep.next243.i: ; preds = %for.loop48.i 962 | %232 = icmp ult i64 %203, 9 963 | tail call void @llvm.assume(i1 %232) #3 964 | %233 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 %203 965 | %234 = load i32, i32* %233, align 4 966 | %235 = icmp eq i32 %234, 0 967 | br i1 %235, label %for.loop48.i, label %for.done51.i 968 | 969 | gep.next249.i: ; preds = %for.done51.i, %for.body55.i 970 | %236 = phi i64 [ %211, %for.body55.i ], [ %65, %for.done51.i ] 971 | %237 = phi i64 [ %210, %for.body55.i ], [ %217, %for.done51.i ] 972 | %238 = icmp ult i64 %237, 9 973 | tail call void @llvm.assume(i1 %238) #3 974 | %239 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 %237 975 | %240 = load i32, i32* %239, align 4 976 | %241 = icmp ult i64 %236, 9 977 | tail call void @llvm.assume(i1 %241) #3 978 | %242 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 %236 979 | %243 = load i32, i32* %242, align 4 980 | %244 = icmp eq i32 %240, %243 981 | br i1 %244, label %for.body55.i, label %gep.next261.i 982 | 983 | gep.next261.i: ; preds = %gep.next249.i, %if.then57.i.gep.next261.i_crit_edge 984 | %245 = phi i32 [ %.pre79, %if.then57.i.gep.next261.i_crit_edge ], [ %240, %gep.next249.i ] 985 | %246 = phi i32 [ %.pre, %if.then57.i.gep.next261.i_crit_edge ], [ %243, %gep.next249.i ] 986 | %.lcssa73131138.i = phi i64 [ %.lcssa73.i, %if.then57.i.gep.next261.i_crit_edge ], [ %237, %gep.next249.i ] 987 | %.lcssa72132137.i = phi i64 [ %.lcssa72.i, %if.then57.i.gep.next261.i_crit_edge ], [ %236, %gep.next249.i ] 988 | %247 = icmp ult i64 %.lcssa72132137.i, 9 989 | tail call void @llvm.assume(i1 %247) #3 990 | %248 = icmp ult i64 %.lcssa73131138.i, 9 991 | tail call void @llvm.assume(i1 %248) #3 992 | %249 = icmp sgt i32 %246, %245 993 | %250 = insertelement <2 x i64> poison, i64 %216, i32 0 994 | %251 = insertelement <2 x i64> %250, i64 %207, i32 1 995 | br i1 %249, label %deref.next111.i, label %if.done12.i 996 | 997 | gep.next271.i: ; preds = %if.else61.i 998 | store i8 0, i8* %1, align 4 999 | %to.repack4.i = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 1 1000 | store i8 %spec.select.i, i8* %to.repack4.i, align 1 1001 | %to.repack8.i = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 3 1002 | %252 = bitcast i1* %to.repack8.i to i8* 1003 | tail call void @llvm.memset.p0i8.i64(i8* noundef nonnull align 1 dereferenceable(37) %252, i8 0, i64 37, i1 false) #3 1004 | br label %doSub.exit 1005 | 1006 | doSub.exit: ; preds = %for.done38.i, %gep.next271.i 1007 | %common.ret.op.i = phi { i64, i32 } [ %170, %for.done38.i ], [ zeroinitializer, %gep.next271.i ] 1008 | %oldret1.i = extractvalue { i64, i32 } %common.ret.op.i, 1 1009 | br label %common.ret 1010 | 1011 | if.done: ; preds = %entry 1012 | br i1 %19, label %if.then.i.i2, label %if.done.i.i3 1013 | 1014 | if.then.i.i2: ; preds = %if.done 1015 | %253 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %18 1016 | %254 = load i64, i64* %253, align 8 1017 | br label %digitsToWords.exit.i5 1018 | 1019 | if.done.i.i3: ; preds = %if.done 1020 | %.lhs.trunc37.i = trunc i64 %18 to i16 1021 | %255 = sdiv i16 %.lhs.trunc37.i, 9 1022 | %.sext38.i = sext i16 %255 to i64 1023 | br label %digitsToWords.exit.i5 1024 | 1025 | digitsToWords.exit.i5: ; preds = %if.done.i.i3, %if.then.i.i2 1026 | %common.ret.op.i.i4 = phi i64 [ %.sext38.i, %if.done.i.i3 ], [ %254, %if.then.i.i2 ] 1027 | %256 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 1 1028 | %257 = load i8, i8* %256, align 1 1029 | %258 = sext i8 %257 to i64 1030 | %259 = add nsw i64 %258, 8 1031 | %260 = icmp ult i64 %259, 128 1032 | br i1 %260, label %if.then.i16.i, label %if.done.i18.i 1033 | 1034 | if.then.i16.i: ; preds = %digitsToWords.exit.i5 1035 | %261 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %259 1036 | %262 = load i64, i64* %261, align 8 1037 | br label %digitsToWords.exit19.i 1038 | 1039 | if.done.i18.i: ; preds = %digitsToWords.exit.i5 1040 | %.lhs.trunc35.i = trunc i64 %259 to i16 1041 | %263 = sdiv i16 %.lhs.trunc35.i, 9 1042 | %.sext36.i = sext i16 %263 to i64 1043 | br label %digitsToWords.exit19.i 1044 | 1045 | digitsToWords.exit19.i: ; preds = %if.done.i18.i, %if.then.i16.i 1046 | %common.ret.op.i17.i = phi i64 [ %.sext36.i, %if.done.i18.i ], [ %262, %if.then.i16.i ] 1047 | %264 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 0 1048 | %265 = load i8, i8* %264, align 1 1049 | %266 = sext i8 %265 to i64 1050 | %267 = add nsw i64 %266, 8 1051 | %268 = icmp ult i64 %267, 128 1052 | br i1 %268, label %if.then.i20.i, label %if.done.i22.i 1053 | 1054 | if.then.i20.i: ; preds = %digitsToWords.exit19.i 1055 | %269 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %267 1056 | %270 = load i64, i64* %269, align 8 1057 | br label %digitsToWords.exit23.i 1058 | 1059 | if.done.i22.i: ; preds = %digitsToWords.exit19.i 1060 | %.lhs.trunc33.i = trunc i64 %267 to i16 1061 | %271 = sdiv i16 %.lhs.trunc33.i, 9 1062 | %.sext34.i = sext i16 %271 to i64 1063 | br label %digitsToWords.exit23.i 1064 | 1065 | digitsToWords.exit23.i: ; preds = %if.done.i22.i, %if.then.i20.i 1066 | %common.ret.op.i21.i = phi i64 [ %.sext34.i, %if.done.i22.i ], [ %270, %if.then.i20.i ] 1067 | %272 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 1 1068 | %273 = load i8, i8* %272, align 1 1069 | %274 = sext i8 %273 to i64 1070 | %275 = add nsw i64 %274, 8 1071 | %276 = icmp ult i64 %275, 128 1072 | br i1 %276, label %if.then.i24.i, label %if.done.i26.i 1073 | 1074 | if.then.i24.i: ; preds = %digitsToWords.exit23.i 1075 | %277 = getelementptr inbounds [128 x i64], [128 x i64]* @div9, i64 0, i64 %275 1076 | %278 = load i64, i64* %277, align 8 1077 | br label %digitsToWords.exit27.i 1078 | 1079 | if.done.i26.i: ; preds = %digitsToWords.exit23.i 1080 | %.lhs.trunc.i6 = trunc i64 %275 to i16 1081 | %279 = sdiv i16 %.lhs.trunc.i6, 9 1082 | %.sext.i7 = sext i16 %279 to i64 1083 | br label %digitsToWords.exit27.i 1084 | 1085 | digitsToWords.exit27.i: ; preds = %if.done.i26.i, %if.then.i24.i 1086 | %common.ret.op.i25.i = phi i64 [ %.sext.i7, %if.done.i26.i ], [ %278, %if.then.i24.i ] 1087 | %280 = icmp sgt i64 %common.ret.op.i.i4, %common.ret.op.i21.i 1088 | %spec.select.i.i8 = select i1 %280, i64 %common.ret.op.i.i4, i64 %common.ret.op.i21.i 1089 | %281 = icmp sgt i64 %common.ret.op.i17.i, %common.ret.op.i25.i 1090 | %spec.select.i28.i = select i1 %281, i64 %common.ret.op.i17.i, i64 %common.ret.op.i25.i 1091 | br i1 %280, label %gep.next46.i, label %if.else30.i 1092 | 1093 | if.done.i: ; preds = %gep.next134.i, %gep.next130.i, %gep.next46.i 1094 | %282 = phi i32 [ %401, %gep.next46.i ], [ %406, %gep.next130.i ], [ %411, %gep.next134.i ] 1095 | %283 = icmp sgt i32 %282, 999999998 1096 | br i1 %283, label %if.then1.i, label %if.done2.i 1097 | 1098 | if.then1.i: ; preds = %if.done.i 1099 | %284 = add i64 %spec.select.i.i8, 1 1100 | %285 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 0 1101 | store i32 0, i32* %285, align 4 1102 | br label %if.done2.i 1103 | 1104 | if.done2.i: ; preds = %if.then1.i, %if.done.i 1105 | %286 = phi i64 [ %spec.select.i.i8, %if.done.i ], [ %284, %if.then1.i ] 1106 | %287 = add i64 %286, %spec.select.i28.i 1107 | %288 = icmp sgt i64 %287, 9 1108 | br i1 %288, label %if.then.i29.i9, label %if.done2.i.i11 1109 | 1110 | if.then.i29.i9: ; preds = %if.done2.i 1111 | %289 = icmp sgt i64 %286, 9 1112 | br i1 %289, label %fixWordCntError.exit.i13, label %if.done.i31.i10 1113 | 1114 | if.done.i31.i10: ; preds = %if.then.i29.i9 1115 | %290 = sub i64 9, %286 1116 | %291 = insertvalue { i64, i64, i32 } zeroinitializer, i64 %286, 0 1117 | %292 = insertvalue { i64, i64, i32 } %291, i64 %290, 1 1118 | %293 = insertvalue { i64, i64, i32 } %292, i32 2, 2 1119 | br label %fixWordCntError.exit.i13 1120 | 1121 | if.done2.i.i11: ; preds = %if.done2.i 1122 | %294 = insertvalue { i64, i64, i32 } zeroinitializer, i64 %286, 0 1123 | %295 = insertvalue { i64, i64, i32 } %294, i64 %spec.select.i28.i, 1 1124 | %296 = insertvalue { i64, i64, i32 } %295, i32 0, 2 1125 | br label %fixWordCntError.exit.i13 1126 | 1127 | fixWordCntError.exit.i13: ; preds = %if.done2.i.i11, %if.done.i31.i10, %if.then.i29.i9 1128 | %common.ret.op.i30.i12 = phi { i64, i64, i32 } [ %293, %if.done.i31.i10 ], [ %296, %if.done2.i.i11 ], [ { i64 9, i64 0, i32 1 }, %if.then.i29.i9 ] 1129 | %297 = extractvalue { i64, i64, i32 } %common.ret.op.i30.i12, 0 1130 | %298 = extractvalue { i64, i64, i32 } %common.ret.op.i30.i12, 1 1131 | %299 = extractvalue { i64, i64, i32 } %common.ret.op.i30.i12, 2 1132 | %300 = icmp eq i32 %299, 1 1133 | br i1 %300, label %if.then3.i, label %if.done4.i 1134 | 1135 | if.then3.i: ; preds = %fixWordCntError.exit.i13 1136 | %301 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 3 1137 | store i1 false, i1* %301, align 1 1138 | store i8 81, i8* %1, align 1 1139 | %302 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 0 1140 | store i32 999999999, i32* %302, align 4 1141 | %303 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 1 1142 | store i32 999999999, i32* %303, align 4 1143 | %304 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 2 1144 | store i32 999999999, i32* %304, align 4 1145 | %305 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 3 1146 | store i32 999999999, i32* %305, align 4 1147 | %306 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 4 1148 | store i32 999999999, i32* %306, align 4 1149 | %307 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 5 1150 | store i32 999999999, i32* %307, align 4 1151 | %308 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 6 1152 | store i32 999999999, i32* %308, align 4 1153 | %309 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 7 1154 | store i32 999999999, i32* %309, align 4 1155 | %310 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 8 1156 | store i32 999999999, i32* %310, align 4 1157 | %311 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 1 1158 | store i8 0, i8* %311, align 1 1159 | br label %common.ret 1160 | 1161 | if.done4.i: ; preds = %fixWordCntError.exit.i13 1162 | %312 = add i64 %297, %298 1163 | %313 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 3 1164 | %314 = load i1, i1* %10, align 1 1165 | store i1 %314, i1* %313, align 1 1166 | %315 = trunc i64 %297 to i8 1167 | %316 = mul i8 %315, 9 1168 | store i8 %316, i8* %1, align 1 1169 | %317 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 1 1170 | %318 = load i8, i8* %256, align 1 1171 | %319 = load i8, i8* %272, align 1 1172 | %320 = icmp sgt i8 %318, %319 1173 | %spec.select.i32.i = select i1 %320, i8 %318, i8 %319 1174 | store i8 %spec.select.i32.i, i8* %317, align 1 1175 | %.not.i14 = icmp eq i32 %299, 0 1176 | %321 = insertelement <4 x i64> poison, i64 %common.ret.op.i25.i, i32 0 1177 | %322 = insertelement <4 x i64> %321, i64 %common.ret.op.i21.i, i32 1 1178 | %323 = insertelement <4 x i64> %322, i64 %common.ret.op.i17.i, i32 2 1179 | %324 = insertelement <4 x i64> %323, i64 %common.ret.op.i.i4, i32 3 1180 | br i1 %.not.i14, label %if.done15.i, label %deref.next78.i 1181 | 1182 | if.done7.i: ; preds = %store.next82.i, %deref.next78.i 1183 | %325 = insertelement <4 x i64> poison, i64 %298, i32 0 1184 | %326 = insertelement <4 x i64> %325, i64 %297, i32 1 1185 | %shuffle = shufflevector <4 x i64> %326, <4 x i64> poison, <4 x i32> 1186 | %327 = icmp sgt <4 x i64> %324, %shuffle 1187 | %shuffle136 = shufflevector <4 x i64> %326, <4 x i64> poison, <4 x i32> 1188 | %328 = select <4 x i1> %327, <4 x i64> %shuffle136, <4 x i64> %324 1189 | br label %if.done15.i 1190 | 1191 | if.done15.i: ; preds = %if.done7.i, %if.done4.i 1192 | %329 = phi <4 x i64> [ %324, %if.done4.i ], [ %328, %if.done7.i ] 1193 | %330 = extractelement <4 x i64> %329, i32 0 1194 | %331 = extractelement <4 x i64> %329, i32 2 1195 | %332 = icmp sgt i64 %331, %330 1196 | br i1 %332, label %if.then16.i, label %if.else27.i 1197 | 1198 | if.then16.i: ; preds = %if.done15.i 1199 | %333 = extractelement <4 x i64> %329, i32 3 1200 | %334 = add i64 %331, %333 1201 | %335 = add i64 %330, %333 1202 | %336 = extractelement <4 x i64> %329, i32 1 1203 | %337 = add i64 %330, %336 1204 | %338 = icmp sgt i64 %333, %336 1205 | %339 = sub i64 %333, %336 1206 | %spec.select142.i = select i1 %338, i64 %339, i64 0 1207 | br label %for.loop.preheader.i16 1208 | 1209 | for.loop.preheader.i16: ; preds = %if.else27.i, %if.then16.i 1210 | %.ph40.i = phi %MyDecimal* [ %from1, %if.then16.i ], [ %from2, %if.else27.i ] 1211 | %.ph41.i = phi %MyDecimal* [ %from2, %if.then16.i ], [ %from1, %if.else27.i ] 1212 | %.ph42.i = phi i64 [ %334, %if.then16.i ], [ %393, %if.else27.i ] 1213 | %.ph43.i = phi i64 [ %337, %if.then16.i ], [ %396, %if.else27.i ] 1214 | %.ph44.i = phi i64 [ %335, %if.then16.i ], [ %394, %if.else27.i ] 1215 | %.ph45.i = phi i64 [ %spec.select142.i, %if.then16.i ], [ %spec.select143.i, %if.else27.i ] 1216 | %340 = icmp sgt i64 %.ph42.i, %.ph44.i 1217 | br i1 %340, label %for.body.i17, label %for.loop18.preheader.i 1218 | 1219 | for.loop18.preheader.i: ; preds = %for.body.i17, %for.loop.preheader.i16 1220 | %.lcssa50.i = phi i64 [ %312, %for.loop.preheader.i16 ], [ %344, %for.body.i17 ] 1221 | %.lcssa49.i = phi i64 [ %.ph42.i, %for.loop.preheader.i16 ], [ %.ph44.i, %for.body.i17 ] 1222 | %341 = icmp sgt i64 %.lcssa49.i, %.ph45.i 1223 | br i1 %341, label %for.body19.i, label %for.done20.i 1224 | 1225 | for.body.i17: ; preds = %for.loop.preheader.i16, %for.body.i17 1226 | %342 = phi i64 [ %345, %for.body.i17 ], [ %.ph42.i, %for.loop.preheader.i16 ] 1227 | %343 = phi i64 [ %344, %for.body.i17 ], [ %312, %for.loop.preheader.i16 ] 1228 | %344 = add nsw i64 %343, -1 1229 | %345 = add nsw i64 %342, -1 1230 | %346 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %344 1231 | %347 = getelementptr inbounds %MyDecimal, %MyDecimal* %.ph40.i, i64 0, i32 4, i64 %345 1232 | %348 = load i32, i32* %347, align 4 1233 | store i32 %348, i32* %346, align 4 1234 | %349 = icmp sgt i64 %345, %.ph44.i 1235 | br i1 %349, label %for.body.i17, label %for.loop18.preheader.i 1236 | 1237 | for.body19.i: ; preds = %for.loop18.preheader.i, %for.body19.i 1238 | %350 = phi i32 [ %366, %for.body19.i ], [ 0, %for.loop18.preheader.i ] 1239 | %351 = phi i64 [ %355, %for.body19.i ], [ %.ph43.i, %for.loop18.preheader.i ] 1240 | %352 = phi i64 [ %354, %for.body19.i ], [ %.lcssa49.i, %for.loop18.preheader.i ] 1241 | %353 = phi i64 [ %356, %for.body19.i ], [ %.lcssa50.i, %for.loop18.preheader.i ] 1242 | %354 = add nsw i64 %352, -1 1243 | %355 = add nsw i64 %351, -1 1244 | %356 = add nsw i64 %353, -1 1245 | %357 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %356 1246 | %358 = getelementptr inbounds %MyDecimal, %MyDecimal* %.ph40.i, i64 0, i32 4, i64 %354 1247 | %359 = load i32, i32* %358, align 4 1248 | %360 = getelementptr inbounds %MyDecimal, %MyDecimal* %.ph41.i, i64 0, i32 4, i64 %355 1249 | %361 = load i32, i32* %360, align 4 1250 | %362 = add i32 %359, %350 1251 | %363 = add i32 %362, %361 1252 | %364 = icmp sgt i32 %363, 999999999 1253 | %365 = add i32 %363, -1000000000 1254 | %366 = zext i1 %364 to i32 1255 | %367 = select i1 %364, i32 %365, i32 %363 1256 | store i32 %367, i32* %357, align 4 1257 | %368 = icmp sgt i64 %354, %.ph45.i 1258 | br i1 %368, label %for.body19.i, label %for.done20.i 1259 | 1260 | for.done20.i: ; preds = %for.body19.i, %for.loop18.preheader.i 1261 | %.lcssa48.i = phi i64 [ %.lcssa50.i, %for.loop18.preheader.i ], [ %356, %for.body19.i ] 1262 | %.lcssa47.i = phi i32 [ 0, %for.loop18.preheader.i ], [ %366, %for.body19.i ] 1263 | %369 = extractelement <4 x i64> %329, i32 1 1264 | %370 = extractelement <4 x i64> %329, i32 3 1265 | %371 = icmp sgt i64 %370, %369 1266 | %372 = sub i64 %369, %370 1267 | %373 = sub i64 %370, %369 1268 | %.ph.i18 = select i1 %371, %MyDecimal* %from1, %MyDecimal* %from2 1269 | %.ph39.i = select i1 %371, i64 %373, i64 %372 1270 | %374 = icmp sgt i64 %.ph39.i, 0 1271 | br i1 %374, label %for.body23.i, label %for.done24.i 1272 | 1273 | for.body23.i: ; preds = %for.done20.i, %for.body23.i 1274 | %375 = phi i32 [ %386, %for.body23.i ], [ %.lcssa47.i, %for.done20.i ] 1275 | %376 = phi i64 [ %379, %for.body23.i ], [ %.ph39.i, %for.done20.i ] 1276 | %377 = phi i64 [ %378, %for.body23.i ], [ %.lcssa48.i, %for.done20.i ] 1277 | %378 = add nsw i64 %377, -1 1278 | %379 = add nsw i64 %376, -1 1279 | %380 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %378 1280 | %381 = getelementptr inbounds %MyDecimal, %MyDecimal* %.ph.i18, i64 0, i32 4, i64 %379 1281 | %382 = load i32, i32* %381, align 4 1282 | %383 = add i32 %382, %375 1283 | %384 = icmp sgt i32 %383, 999999999 1284 | %385 = add i32 %383, -1000000000 1285 | %386 = zext i1 %384 to i32 1286 | %387 = select i1 %384, i32 %385, i32 %383 1287 | store i32 %387, i32* %380, align 4 1288 | %388 = icmp sgt i64 %376, 1 1289 | br i1 %388, label %for.body23.i, label %for.done24.i 1290 | 1291 | for.done24.i: ; preds = %for.body23.i, %for.done20.i 1292 | %.lcssa46.i = phi i64 [ %.lcssa48.i, %for.done20.i ], [ %378, %for.body23.i ] 1293 | %.lcssa.i19 = phi i32 [ %.lcssa47.i, %for.done20.i ], [ %386, %for.body23.i ] 1294 | %389 = icmp sgt i32 %.lcssa.i19, 0 1295 | br i1 %389, label %if.then25.i, label %common.ret 1296 | 1297 | if.then25.i: ; preds = %for.done24.i 1298 | %390 = add nsw i64 %.lcssa46.i, -1 1299 | %391 = getelementptr inbounds %MyDecimal, %MyDecimal* %to, i64 0, i32 4, i64 %390 1300 | store i32 1, i32* %391, align 4 1301 | br label %common.ret 1302 | 1303 | if.else27.i: ; preds = %if.done15.i 1304 | %392 = extractelement <4 x i64> %329, i32 1 1305 | %393 = add i64 %330, %392 1306 | %394 = add i64 %392, %331 1307 | %395 = extractelement <4 x i64> %329, i32 3 1308 | %396 = add i64 %331, %395 1309 | %397 = icmp sgt i64 %392, %395 1310 | %398 = sub i64 %392, %395 1311 | %spec.select143.i = select i1 %397, i64 %398, i64 0 1312 | br label %for.loop.preheader.i16 1313 | 1314 | if.else30.i: ; preds = %digitsToWords.exit27.i 1315 | %399 = icmp sgt i64 %common.ret.op.i21.i, %common.ret.op.i.i4 1316 | br i1 %399, label %gep.next130.i, label %gep.next134.i 1317 | 1318 | gep.next46.i: ; preds = %digitsToWords.exit27.i 1319 | %400 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 0 1320 | %401 = load i32, i32* %400, align 4 1321 | br label %if.done.i 1322 | 1323 | deref.next78.i: ; preds = %if.done4.i 1324 | %402 = trunc i64 %298 to i8 1325 | %403 = mul i8 %402, 9 1326 | %404 = icmp sgt i8 %spec.select.i32.i, %403 1327 | br i1 %404, label %store.next82.i, label %if.done7.i 1328 | 1329 | store.next82.i: ; preds = %deref.next78.i 1330 | store i8 %403, i8* %317, align 1 1331 | br label %if.done7.i 1332 | 1333 | gep.next130.i: ; preds = %if.else30.i 1334 | %405 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 0 1335 | %406 = load i32, i32* %405, align 4 1336 | br label %if.done.i 1337 | 1338 | gep.next134.i: ; preds = %if.else30.i 1339 | %407 = getelementptr inbounds %MyDecimal, %MyDecimal* %from1, i64 0, i32 4, i64 0 1340 | %408 = load i32, i32* %407, align 4 1341 | %409 = getelementptr inbounds %MyDecimal, %MyDecimal* %from2, i64 0, i32 4, i64 0 1342 | %410 = load i32, i32* %409, align 4 1343 | %411 = add i32 %410, %408 1344 | br label %if.done.i 1345 | } 1346 | 1347 | ; Function Attrs: inaccessiblememonly nofree nosync nounwind willreturn 1348 | declare void @llvm.assume(i1 noundef) #1 1349 | 1350 | ; Function Attrs: argmemonly nofree nounwind willreturn writeonly 1351 | declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #2 1352 | 1353 | attributes #0 = { nofree nosync nounwind } 1354 | attributes #1 = { inaccessiblememonly nofree nosync nounwind willreturn } 1355 | attributes #2 = { argmemonly nofree nounwind willreturn writeonly } 1356 | attributes #3 = { nounwind } 1357 | --------------------------------------------------------------------------------