📜 ⬆️ ⬇️

Simple test libjit vs llvm

"And experience, son of difficult mistakes" (c) You know who

Since childhood, I was interested in questions like " who wins - an elephant or a whale ." Or, for example, " who is stronger - a tiger or a lion ." Now that I’ve grown up, the questions have changed a bit. Now I'm interested in particular - which is cooler than libjit or llvm .

It is clear that a simple way to answer such a question is not products that have ecological niches that do not completely coincide, but you can always write a simple test and see how pleasant it was to write, how fast the result is being fulfilled, and at least make impressions about the products from laudatory articles and, so to speak, personal experience.
')

So. A simple task is the sieve of Eratosthenes, or the search for prime numbers.



I took the implementation for the basics, which is listed in Wikipedia, to which I added a cycle to launch the eratosthene sieve many times. It turned out like this:

001 : program erato ;
002:
003: procedure eratosphen (n : integer ) ;
004: var
005: a : array [ 0 .. 100000 ] of byte ;
006: q : integer ;
007: i , j : integer ;
008: begin
009: FillChar (a , sizeof (a) , 1 ) ;
010: q := round ( sqrt (n)) ;
011: for i := 2 to q do
012: if a[i] = 1 then
013: begin
014: j := i * i ;
015: while j <= n do
016: begin
017: a[j] := 0 ;
018: j := j + i ;
019: end ;
020: end ;
021: end ;
022:
023: var i : integer ;
024: begin
025: Writeln ( 'Poexali' ) ;
026: for i := 1 to 5000 do
027: eratosphen( 100000 ) ;
028: end .
029:


LIBJIT option


When using libjit, you get this program:

001 : #include <stdio.h>
002: #include <jit/jit.h>
003:

004: unsigned int myprint ( unsigned int a) {
005: printf( " %d \n " ,a);
006: }
007:
008: jit_function_t main_function, erato;
009:
010:
011: void create_erato ()
012: {
013: jit_type_t params[ 1 ];
014: jit_type_t signature;
015: jit_label_t for_begin = jit_label_undefined;
016: jit_label_t end_for = jit_label_undefined;
017: jit_label_t end_if = jit_label_undefined;
018: jit_label_t while_end = jit_label_undefined;
019: jit_label_t while_begin = jit_label_undefined;
020: jit_label_t print_end = jit_label_undefined;
021: jit_label_t print_begin = jit_label_undefined;
022: jit_label_t print_if = jit_label_undefined;
023: void * args[ 2 ];
024: jit_uint result;
025: jit_value_t n,a,one1,szero,uint1,two2;
026: jit_int arg1;
027: jit_intrinsic_descr_t tofloat = {jit_type_nfloat, NULL , jit_type_uint, NULL };
028: jit_intrinsic_descr_t toint = {jit_type_uint, NULL , jit_type_nfloat, NULL };
029: jit_value_t temp1,temp2,q;
030: jit_value_t i,j,elem;
031: jit_value_t for_cond, if_cond, while_cond, print_cond;
032: jit_value_t tmpi, tmp3,tmp4;
033: /* Create a context to hold the JIT's primary state */
034: /* Build the erato signature */
035: params[ 0 ] = jit_type_uint;
036: signature = jit_type_create_signature (jit_abi_cdecl, jit_type_uint, params, 1 , 1 );
037:
038: /* allocate sieve storage and init it by 1 */
039: n = jit_value_get_param(erato, 0 );
040:
041: //jit_insn_call_native(erato, "print", myprint, signature, &n ,1,0);
042:
a = jit_insn_alloca(erato,n);
043: one1 = jit_value_create_nint_constant(erato, jit_type_ubyte, 1 );
044: szero = jit_value_create_nint_constant(erato,jit_type_ubyte, 0 );
045: jit_insn_memset(erato,a, one1,n);
046: /* convert to float, sqrt and convert to int back */
047: temp1 = jit_insn_call_intrinsic(erato, "convert_to_float" , jit_uint_to_nfloat, & tofloat ,n, NULL );
048: temp2 = jit_insn_sqrt(erato, temp1);
049: q = jit_insn_call_intrinsic(erato, "convert_to_int" ,jit_nfloat_to_uint, & toint ,temp2, NULL );
050:
051: /* for i = 2 to q do*/
052: two2 = jit_value_create_nint_constant(erato,jit_type_uint, 2 );
053: i = jit_value_create(erato,jit_type_uint);
054: jit_insn_store(erato,i,two2);
055: jit_insn_label(erato, & for_begin);
056: for_cond = jit_insn_gt(erato, i, q);
057: jit_insn_branch_if(erato,for_cond, & end_for);
058:
059: // if
060:
elem = jit_insn_load_elem(erato, a, i, jit_type_ubyte);
061: if_cond = jit_insn_eq(erato, elem, one1);
062: jit_insn_branch_if_not(erato,if_cond, & end_if);
063:
064: // j = i*i
065:
j = jit_value_create(erato, jit_type_uint);
066: tmp3 = jit_insn_mul(erato, i, i);
067: jit_insn_store(erato,j, tmp3);
068:
069: // while
070:
jit_insn_label(erato, & while_begin);
071: while_cond = jit_insn_gt(erato,j,n);
072: jit_insn_branch_if(erato, while_cond, & while_end);
073:
074: jit_insn_store_elem(erato,a,j,szero);
075:
076: tmp4 = jit_insn_add(erato,j,i);
077: jit_insn_store(erato,j,tmp4);
078: //while end
079:
jit_insn_branch(erato, & while_begin);
080: jit_insn_label(erato, & while_end);
081: // end if
082:
jit_insn_label(erato, & end_if);
083:
084: // end for i=2 to q
085:
uint1 = jit_value_create_nint_constant(erato,jit_type_uint, 1 );
086: tmpi = jit_insn_add(erato,i,uint1);
087: jit_insn_store(erato,i,tmpi);
088: jit_insn_branch(erato, & for_begin);
089: jit_insn_label(erato, & end_for);
090:
091: jit_insn_return(erato, i);
092:
093: /* Compile the erato */
094: jit_dump_function(stderr, erato, "erato" );
095:
096: jit_function_compile(erato);
097: }
098:
099:
100: void create_main ()
101: {
102: jit_label_t for_begin = jit_label_undefined;
103: jit_label_t end_for = jit_label_undefined;
104: jit_value_t temp_args[ 1 ];
105: jit_value_t temp3,tmpi,one,n,the_i,for_cond,alot,place_for_i;
106: jit_type_t params[ 2 ];
107: jit_type_t signature;
108:
109: n = jit_value_get_param(main_function, 0 );
110: alot = jit_value_get_param(main_function, 1 );
111:
112: one = jit_value_create_nint_constant(main_function,jit_type_int, 1 );
113: the_i = jit_value_create(main_function,jit_type_uint);
114:
115: place_for_i = jit_insn_alloca(main_function, jit_value_create_nint_constant(main_function,jit_type_int, 4 ) );
116:
117: jit_insn_store(main_function,place_for_i,one);
118:
119: jit_insn_label(main_function, & for_begin);
120: the_i = jit_insn_load(main_function,place_for_i);
121:
122: for_cond = jit_insn_gt(main_function, the_i, n);
123: jit_insn_branch_if(main_function,for_cond, & end_for);
124:
125: temp_args[ 0 ] = alot;
126: tmpi = jit_insn_call (main_function, "erato" , erato, NULL , temp_args, 1 , JIT_CALL_NOTHROW);
127:
128: temp3 = jit_insn_add(main_function,the_i,one);
129:
130: jit_insn_store(main_function,place_for_i,temp3);
131:
132: jit_insn_branch(main_function, & for_begin);
133: jit_insn_label(main_function, & end_for);
134:
135: jit_insn_return(main_function, alot);
136:
137: jit_dump_function(stderr, main_function, "main" );
138: jit_function_compile(main_function);
139: // jit_dump_function(stderr, main_function, "main_compiled");
140:

141: }
142:
143: int main ( int argc, char ** argv)
144: {
145: jit_context_t context;
146: void * args[ 2 ];
147: jit_uint result;
148: jit_int arg1,arg2;
149: jit_type_t params[ 2 ];
150: jit_type_t signature,sign1;
151:
152: context = jit_context_create();
153:
154: /* Lock the context while we build and compile the function */
155: jit_context_build_start(context);
156:
157: /* Build the function signature */
158: params[ 0 ] = jit_type_int;
159: signature = jit_type_create_signature (jit_abi_cdecl, jit_type_int, params, 1 , 1 );
160:
161: erato = jit_function_create(context, signature);
162: create_erato();
163:
164: params[ 0 ] = jit_type_int;
165: params[ 1 ] = jit_type_int;
166: signature = jit_type_create_signature (jit_abi_cdecl, jit_type_int, params, 2 , 1 );
167:
168: main_function = jit_function_create(context, signature);
169: create_main();
170:
171: /* Unlock the context */
172: jit_context_build_end(context);
173:
174: // jit_dump_function(stderr, main_function, "main");
175:
/* Execute the function and print the result */
176: arg1 = 100000 ;
177: arg2 = 50000 ;
178: args[ 0 ] = & arg1;
179: args[ 1 ] = & arg2;
180:
181: jit_function_apply(main_function, args, & result);
182:
183: /* Clean up */
184: jit_context_destroy(context);
185:
186: /* Finished */
187: return 0 ;
188: }
189:

001 : #include <stdio.h>
002: #include <jit/jit.h>
003:

004: unsigned int myprint ( unsigned int a) {
005: printf( " %d \n " ,a);
006: }
007:
008: jit_function_t main_function, erato;
009:
010:
011: void create_erato ()
012: {
013: jit_type_t params[ 1 ];
014: jit_type_t signature;
015: jit_label_t for_begin = jit_label_undefined;
016: jit_label_t end_for = jit_label_undefined;
017: jit_label_t end_if = jit_label_undefined;
018: jit_label_t while_end = jit_label_undefined;
019: jit_label_t while_begin = jit_label_undefined;
020: jit_label_t print_end = jit_label_undefined;
021: jit_label_t print_begin = jit_label_undefined;
022: jit_label_t print_if = jit_label_undefined;
023: void * args[ 2 ];
024: jit_uint result;
025: jit_value_t n,a,one1,szero,uint1,two2;
026: jit_int arg1;
027: jit_intrinsic_descr_t tofloat = {jit_type_nfloat, NULL , jit_type_uint, NULL };
028: jit_intrinsic_descr_t toint = {jit_type_uint, NULL , jit_type_nfloat, NULL };
029: jit_value_t temp1,temp2,q;
030: jit_value_t i,j,elem;
031: jit_value_t for_cond, if_cond, while_cond, print_cond;
032: jit_value_t tmpi, tmp3,tmp4;
033: /* Create a context to hold the JIT's primary state */
034: /* Build the erato signature */
035: params[ 0 ] = jit_type_uint;
036: signature = jit_type_create_signature (jit_abi_cdecl, jit_type_uint, params, 1 , 1 );
037:
038: /* allocate sieve storage and init it by 1 */
039: n = jit_value_get_param(erato, 0 );
040:
041: //jit_insn_call_native(erato, "print", myprint, signature, &n ,1,0);
042:
a = jit_insn_alloca(erato,n);
043: one1 = jit_value_create_nint_constant(erato, jit_type_ubyte, 1 );
044: szero = jit_value_create_nint_constant(erato,jit_type_ubyte, 0 );
045: jit_insn_memset(erato,a, one1,n);
046: /* convert to float, sqrt and convert to int back */
047: temp1 = jit_insn_call_intrinsic(erato, "convert_to_float" , jit_uint_to_nfloat, & tofloat ,n, NULL );
048: temp2 = jit_insn_sqrt(erato, temp1);
049: q = jit_insn_call_intrinsic(erato, "convert_to_int" ,jit_nfloat_to_uint, & toint ,temp2, NULL );
050:
051: /* for i = 2 to q do*/
052: two2 = jit_value_create_nint_constant(erato,jit_type_uint, 2 );
053: i = jit_value_create(erato,jit_type_uint);
054: jit_insn_store(erato,i,two2);
055: jit_insn_label(erato, & for_begin);
056: for_cond = jit_insn_gt(erato, i, q);
057: jit_insn_branch_if(erato,for_cond, & end_for);
058:
059: // if
060:
elem = jit_insn_load_elem(erato, a, i, jit_type_ubyte);
061: if_cond = jit_insn_eq(erato, elem, one1);
062: jit_insn_branch_if_not(erato,if_cond, & end_if);
063:
064: // j = i*i
065:
j = jit_value_create(erato, jit_type_uint);
066: tmp3 = jit_insn_mul(erato, i, i);
067: jit_insn_store(erato,j, tmp3);
068:
069: // while
070:
jit_insn_label(erato, & while_begin);
071: while_cond = jit_insn_gt(erato,j,n);
072: jit_insn_branch_if(erato, while_cond, & while_end);
073:
074: jit_insn_store_elem(erato,a,j,szero);
075:
076: tmp4 = jit_insn_add(erato,j,i);
077: jit_insn_store(erato,j,tmp4);
078: //while end
079:
jit_insn_branch(erato, & while_begin);
080: jit_insn_label(erato, & while_end);
081: // end if
082:
jit_insn_label(erato, & end_if);
083:
084: // end for i=2 to q
085:
uint1 = jit_value_create_nint_constant(erato,jit_type_uint, 1 );
086: tmpi = jit_insn_add(erato,i,uint1);
087: jit_insn_store(erato,i,tmpi);
088: jit_insn_branch(erato, & for_begin);
089: jit_insn_label(erato, & end_for);
090:
091: jit_insn_return(erato, i);
092:
093: /* Compile the erato */
094: jit_dump_function(stderr, erato, "erato" );
095:
096: jit_function_compile(erato);
097: }
098:
099:
100: void create_main ()
101: {
102: jit_label_t for_begin = jit_label_undefined;
103: jit_label_t end_for = jit_label_undefined;
104: jit_value_t temp_args[ 1 ];
105: jit_value_t temp3,tmpi,one,n,the_i,for_cond,alot,place_for_i;
106: jit_type_t params[ 2 ];
107: jit_type_t signature;
108:
109: n = jit_value_get_param(main_function, 0 );
110: alot = jit_value_get_param(main_function, 1 );
111:
112: one = jit_value_create_nint_constant(main_function,jit_type_int, 1 );
113: the_i = jit_value_create(main_function,jit_type_uint);
114:
115: place_for_i = jit_insn_alloca(main_function, jit_value_create_nint_constant(main_function,jit_type_int, 4 ) );
116:
117: jit_insn_store(main_function,place_for_i,one);
118:
119: jit_insn_label(main_function, & for_begin);
120: the_i = jit_insn_load(main_function,place_for_i);
121:
122: for_cond = jit_insn_gt(main_function, the_i, n);
123: jit_insn_branch_if(main_function,for_cond, & end_for);
124:
125: temp_args[ 0 ] = alot;
126: tmpi = jit_insn_call (main_function, "erato" , erato, NULL , temp_args, 1 , JIT_CALL_NOTHROW);
127:
128: temp3 = jit_insn_add(main_function,the_i,one);
129:
130: jit_insn_store(main_function,place_for_i,temp3);
131:
132: jit_insn_branch(main_function, & for_begin);
133: jit_insn_label(main_function, & end_for);
134:
135: jit_insn_return(main_function, alot);
136:
137: jit_dump_function(stderr, main_function, "main" );
138: jit_function_compile(main_function);
139: // jit_dump_function(stderr, main_function, "main_compiled");
140:

141: }
142:
143: int main ( int argc, char ** argv)
144: {
145: jit_context_t context;
146: void * args[ 2 ];
147: jit_uint result;
148: jit_int arg1,arg2;
149: jit_type_t params[ 2 ];
150: jit_type_t signature,sign1;
151:
152: context = jit_context_create();
153:
154: /* Lock the context while we build and compile the function */
155: jit_context_build_start(context);
156:
157: /* Build the function signature */
158: params[ 0 ] = jit_type_int;
159: signature = jit_type_create_signature (jit_abi_cdecl, jit_type_int, params, 1 , 1 );
160:
161: erato = jit_function_create(context, signature);
162: create_erato();
163:
164: params[ 0 ] = jit_type_int;
165: params[ 1 ] = jit_type_int;
166: signature = jit_type_create_signature (jit_abi_cdecl, jit_type_int, params, 2 , 1 );
167:
168: main_function = jit_function_create(context, signature);
169: create_main();
170:
171: /* Unlock the context */
172: jit_context_build_end(context);
173:
174: // jit_dump_function(stderr, main_function, "main");
175:
/* Execute the function and print the result */
176: arg1 = 100000 ;
177: arg2 = 50000 ;
178: args[ 0 ] = & arg1;
179: args[ 1 ] = & arg2;
180:
181: jit_function_apply(main_function, args, & result);
182:
183: /* Clean up */
184: jit_context_destroy(context);
185:
186: /* Finished */
187: return 0 ;
188: }
189:



General impressions - it is written quite easily, documentation is detailed, there are examples, so - I put +

LLVM option


001 : #include "llvm/DerivedTypes.h"
002: #include "llvm/LLVMContext.h"
003: #include "llvm/Module.h"
004: #include "llvm/Analysis/Verifier.h"
005: #include "llvm/Support/IRBuilder.h"
006: #include "llvm/ExecutionEngine/ExecutionEngine.h"
007: #include "llvm/ExecutionEngine/JIT.h"
008: #include "llvm/PassManager.h"
009: #include "llvm/Analysis/Verifier.h"
010: #include "llvm/Target/TargetData.h"
011: #include "llvm/Target/TargetSelect.h"
012: #include "llvm/Transforms/Scalar.h"
013:
014: #include <iostream>
015: #include <vector>
016: #include <list>
017: #include <map>
018: #include <stdlib.h>
019: #include <cstring>
020: #include <string>
021: #include <stdio.h>
022:
using namespace llvm;
023: using namespace std;
024:
025: Value * ErrorV( const char * Str)
026: {
027: cerr << Str << endl;
028: return 0 ;
029: }
030:
031: static Module * TheModule;
032: static IRBuilder <> Builder(getGlobalContext());
033: static map < string, Value * > NamedValues;
034: static ExecutionEngine * TheExecutionEngine;
035:
036: int main()
037: {
038: InitializeNativeTarget();
039: LLVMContext & Context = getGlobalContext();
040: TheModule = new Module( "erato" , Context);
041:
042: std :: string ErrStr;
043: TheExecutionEngine =
044: EngineBuilder(TheModule).setErrorStr( & ErrStr).create();
045: if ( ! TheExecutionEngine) {
046: fprintf(stderr, "Could not create ExecutionEngine: %s \n " ,
047: ErrStr.c_str());
048: exit( 1 );
049: }
050:
051:
052: const Type * voidType = Type :: getVoidTy(Context);
053: const Type * i32Type = IntegerType :: get(Context, 32 );
054: const Type * i8Type = IntegerType :: get(Context, 8 );
055: const Type * FType = Type :: getDoubleTy(Context);
056: const Type * SType = PointerType :: get(i8Type, 0 );
057:
058: Value * zero = ConstantInt :: get(i32Type, 0 );
059: Value * one = ConstantInt :: get(i32Type, 1 );
060: Value * two = ConstantInt :: get(i32Type, 2 );
061: Constant * n100000 = ConstantInt :: get(i32Type, 100000 );
062: Constant * n50000 = ConstantInt :: get(i32Type, 50000 );
063:
064: Value * i8zero = ConstantInt :: get(i8Type, 0 );
065: Value * i8one = ConstantInt :: get(i8Type, 1 );
066:
067:
068:
069: vector < const Type *> def_args;
070:
071: def_args.push_back(SType);
072: FunctionType * fdefinition = FunctionType :: get(voidType, def_args, true );
073: func_printf = Function :: Create(fdefinition, GlobalValue :: ExternalLinkage, "printf" , TheModule);
074: func_printf -> setCallingConv(CallingConv :: C);
075: def_args.clear();
076:
077: // declare double @llvm.sqrt.f64(double) nounwind readonly
078:

079: def_args.push_back(FType);
080: FunctionType * fdefinition_sqrt = FunctionType :: get(FType, def_args, false );
081: Function * func_sqrt = Function :: Create(fdefinition_sqrt, GlobalValue :: ExternalLinkage, "llvm.sqrt.f64" , TheModule);
082: func_sqrt -> setCallingConv(CallingConv :: C);
083: def_args.clear();
084:
085: // declare void @llvm.memset.i32(i8* nocapture, i8, i32, i32) nounwind
086:

087: def_args.push_back(SType);
088: def_args.push_back(i8Type);
089: def_args.push_back(i32Type);
090: def_args.push_back(i32Type);
091: FunctionType * fdefinition_memset = FunctionType :: get(voidType, def_args, false );
092: Function * func_memset = Function :: Create(fdefinition_memset, GlobalValue :: ExternalLinkage, "llvm.memset.i32" , TheModule);
093: func_memset -> setCallingConv(CallingConv :: C);
094: def_args.clear();
095:
096:
097: // Construct eratosphene()
098:
Function * func_ef = cast < Function > (TheModule -> getOrInsertFunction( "erato" , voidType, i32Type, NULL ));
099: func_ef -> setCallingConv(CallingConv :: C);
100: BasicBlock * ef_start_block = BasicBlock :: Create(Context, "efcode" , func_ef);
101: IRBuilder <> efcodeIR(ef_start_block);
102: format = efcodeIR.CreateGlobalStringPtr( "%d" , ".format" );
103:
104: BasicBlock * ef_mainloop = BasicBlock :: Create(Context, "Main_loop" , func_ef);
105: BasicBlock * ef_mainloopbody = BasicBlock :: Create(Context, "Main_loop.body" , func_ef);
106: BasicBlock * ef_ifbody = BasicBlock :: Create(Context, "if.body" , func_ef);
107: BasicBlock * ef_whileloop = BasicBlock :: Create(Context, "While_loop" , func_ef);
108: BasicBlock * ef_whileloopbody = BasicBlock :: Create(Context, "While_loop.body" , func_ef);
109: BasicBlock * ef_mainloopcont = BasicBlock :: Create(Context, "Main_loop.cont" , func_ef);
110: BasicBlock * ef_mainloopend = BasicBlock :: Create(Context, "Main_loop.end" , func_ef);
111:
112: // Set name for argument
113:
Function :: arg_iterator ef_args = func_ef -> arg_begin();
114: Argument * upbound = ef_args;
115: upbound -> setName( "upbound" );
116:
117: Value * a = efcodeIR.CreateAlloca(i8Type, upbound, "a" );
118: Value * temp1 = efcodeIR.CreateUIToFP(upbound, FType, "tmp.1" );
119: Value * temp2 = efcodeIR.CreateCall(func_sqrt, temp1, "temp.2" );
120: Value * q = efcodeIR.CreateFPToUI(temp2, i32Type, "q" );
121: efcodeIR.CreateCall4(func_memset, a, i8one, upbound, one);
122: efcodeIR.CreateBr(ef_mainloop);
123: efcodeIR.SetInsertPoint(ef_mainloop);
124: PHINode * i = efcodeIR.CreatePHI(i32Type, "i" );
125: i -> addIncoming(two, ef_start_block);
126: Value * cond = efcodeIR.CreateICmpUGT(i, q, "cond" );
127: efcodeIR.CreateCondBr(cond, ef_mainloopend, ef_mainloopbody);
128: efcodeIR.SetInsertPoint(ef_mainloopbody);
129: Value * eptr = efcodeIR.CreateGEP(a, i, "eptr" );
130: Value * elem = efcodeIR.CreateLoad(eptr, "elem" );
131: Value * ifcond = efcodeIR.CreateICmpEQ(i8zero, elem, "ifcond" );
132: efcodeIR.CreateCondBr(ifcond, ef_mainloopcont, ef_ifbody);
133: efcodeIR.SetInsertPoint(ef_ifbody);
134: Value * jfirst = efcodeIR.CreateMul(i, i, "j.first" );
135: efcodeIR.CreateBr(ef_whileloop);
136: efcodeIR.SetInsertPoint(ef_whileloop);
137: PHINode * j = efcodeIR.CreatePHI(i32Type, "j" );
138: j -> addIncoming(jfirst, ef_ifbody);
139: Value * whilecond = efcodeIR.CreateICmpUGT(j, upbound, "while.cond" );
140: efcodeIR.CreateCondBr(whilecond, ef_mainloopcont, ef_whileloopbody);
141: efcodeIR.SetInsertPoint(ef_whileloopbody);
142: Value * elemref = efcodeIR.CreateGEP(a, j, "elem.ref" );
143: efcodeIR.CreateStore(i8zero, elemref);
144: Value * jnext = efcodeIR.CreateAdd(j, i, "j.next" );
145: j -> addIncoming(jnext, ef_whileloopbody);
146: efcodeIR.CreateBr(ef_whileloop);
147: efcodeIR.SetInsertPoint(ef_mainloopcont);
148: Value * inext = efcodeIR.CreateAdd(i, one, "i.next" );
149: i -> addIncoming(inext, ef_mainloopcont);
150: efcodeIR.CreateBr(ef_mainloop);
151:
152: efcodeIR.SetInsertPoint(ef_mainloopend);
153: efcodeIR.CreateRetVoid();
154:
155: // Contruct void main()
156:
Function * func_main = cast < Function > (TheModule -> getOrInsertFunction( "main" , voidType, NULL ));
157: func_main -> setCallingConv(CallingConv :: C);
158: BasicBlock * mnblock = BasicBlock :: Create(Context, "maincode" , func_main);
159: IRBuilder <> mainIR(mnblock);
160:
161: BasicBlock * mn_testloop = BasicBlock :: Create(Context, "Test_loop" , func_main);
162: BasicBlock * mn_tloopbody = BasicBlock :: Create(Context, "Tloop_body" , func_main);
163: BasicBlock * mn_endloop = BasicBlock :: Create(Context, "End_loop" , func_main);
164:
165: mainIR.CreateBr(mn_testloop);
166: mainIR.SetInsertPoint(mn_testloop);
167: PHINode * maini = mainIR.CreatePHI(i32Type, "i" );
168: maini -> addIncoming(zero, mnblock);
169: Value * mainloopcond = mainIR.CreateICmpUGT(maini, n100000, "loop_cond" );
170: mainIR.CreateCondBr(mainloopcond, mn_endloop, mn_tloopbody);
171: mainIR.SetInsertPoint(mn_tloopbody);
172: mainIR.CreateCall(func_ef, n50000);
173: Value * maininext = mainIR.CreateAdd(maini, one, "i.next" );
174: maini -> addIncoming(maininext, mn_tloopbody);
175: mainIR.CreateBr(mn_testloop);
176: mainIR.SetInsertPoint(mn_endloop);
177: mainIR.CreateRetVoid();
178:
179: TheModule -> dump();
180:
181: void * FPtr = TheExecutionEngine -> getPointerToFunction(func_main);
182: void ( * FP) () = ( void ( * )()) FPtr;
183: FP();
184: }
185:


So, we compare:

By verbosity - almost nostril in the nostril. Both here and there you can throw out a couple of lines / comments or add a couple of lines, but this does not make the weather - the size of the code is about the same.

By speed -
LibJit option:

walrus@home:~/sand/erato$ gcc t2_test.c -o ts -ljit
walrus@home:~/sand/erato$ for i in `seq 1 10`; do /usr/bin/time -f '%U' ./ts; done
14.22
14.17
14.12
14.19
14.18
14.24
14.15
14.14
14.15
14.15

Average 14.17 seconds

LLVM option -
walrus@home:~/sand/erato/llvm$ g++ ts.cc -o ts `llvm-config --cxxflags --libs` -lrt -ldl
walrus@home:~/sand/erato/llvm$ for i in `seq 1 10`; do /usr/bin/time -f '%U' ./ts; done
13.83
13.75
13.82
13.76
13.76
13.78
13.76
13.76
13.76
13.76

The average is 13.77 seconds.

The difference was 2.88% in favor of llvm.

By the way, a similar C program prepared with gcc -O1 gave the same 13.79 seconds.

On ambush - llvm unpleasant features unnoticed. Do libjit - this dog does not save the value of registers when calling a function! All that is needed to remain intact, it is better to keep in memory before calling any function. As its jibjit-ovskoy, and external. I didn't find it in the documentation, and spent a couple of hours trying to understand what kind of trouble it was. The problem was finally clarified only by viewing the generated assembler.

Morality



Uh ... I can't figure out what the moral is here

Source: https://habr.com/ru/post/99786/


All Articles