Repository navigation
Expand file tree
/
Copy pathcodegen.ml
More file actions
1331 lines (1248 loc) · 82.1 KB
/
Copy pathcodegen.ml
File metadata and controls
1331 lines (1248 loc) · 82.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* Code generation: translate takes a semantically checked AST and
produces LLVM IR
LLVM tutorial: Make sure to read the OCaml version of the tutorial
http://llvm.org/docs/tutorial/index.html
Detailed documentation on the OCaml LLVM library:
http://llvm.moe/
http://llvm.moe/ocaml/
*)
module L = Llvm
module A = Ast
module M = Matrix
module H = Hashtbl
(*open Str*)
module StringMap = Map.Make(String)
type ret_typ = Returnstruct of L.lltype | Lltypearray of L.lltype array | Voidtype of L.lltype | Maintype
type access_link = Access of access_link * (string, L.llvalue) H.t | Null
let translate (functions, main_stmt) =
(* sample code structure
1. default value: int:0 ; double:0. ; bool:true ; string:"" ; matrix:[]
2. matrix operation:
for each operation below: matrix dimension must agree
i). matrix number element-wise : matrix op number | number op matrix (op : + - * / )
ii). matrix matrix element-wise : matrix op matrix (op : + - * / $)
iii). matrix product : matrix .* matrix
iv). matrix indexing : matrix[x1, y1] | matrix[x1:x2, y1:y2] | matrix[x1:, y1] | matrix[:, y1] | matrix[:, :y2] | etc. basically the syntax of Matlab.
v). matrix assignment : m1 = m2[x1:x2, y1:y2] | m1[x:, :y] = m2[x1:x2, y1:y2] | etc.
vi). matrix equality and inequality : m1 == m2 | m1[x1:, :] != m2[x2:x3, y1:y2] | etc.
3. built-in functions :
i). size : syntax : i, j = size(m), return size of a matrix.
ii). zeros: syntax : zeros(i, j), return a zero matrix of size i by j.
iii). int2double : syntax : int2double(i), convert an int to double.
iv). double2int : syntax : double2int(d), convert a double to int.
v). save(m_r, m_g, m_b, path) : save image to path.
vi). m_r, m_g, m_b = load(path) : load image.
vii). m = face(path) : detect faces in the image at given path, return m is a 4 by n matrix, n is the number of faces, row 1 stores coordinates of the center of faces at which row, row 2 stores coordinates of the center of faces at which col, row 3 stores the height of the faces, row 4 stores the length of faces.
4. std functions:
5. error messages:
i). Compiler error : used for debug purpose, it's very unlikely that user would see any of them.
ii). Syntax error : followed by a description on the error.
iii). Semantic error : followed by description on the error.
func f1(...) { return;}
func f2(matrix m, int i, double d, string s) { return m1, m2, d1, s1;}
matrix m1 = [1.0,2.0;3.0,4.0];
matrix m2;
double d1 =3.4;
string s;
m1[1:,:], m2, d1, s = f2([1.0;3.0], 5, 2.3, "facelab");
*)
(* 1. Auxiliary definitions *)
let context = L.global_context () in
let the_module = L.create_module context "Facelab"
and double_t = L.double_type context
and i32_t = L.i32_type context
and i8_t = L.i8_type context in
let str_t = L.pointer_type i8_t
and i1_t = L.i1_type context
and void_t = L.void_type context in
let matrix_t = L.named_struct_type context "matrix_t" in
L.struct_set_body matrix_t [|L.pointer_type double_t; i32_t; i32_t|] false;
(* declare main first, so that some of the global variables can be stored in the stack of main. Its body will be populated in later section *)
let main_name = "main" in
let main_define = (* main_define the "the_function" equivalent of main function *)
let main_formal = [| |] in (* empty array *)
let main_type = L.function_type i32_t main_formal in
L.define_function main_name main_type the_module in
let main_builder = ref (* main_builder the "builder" equivalent of main function *)
(L.builder_at_end context (L.entry_block main_define)) in
let function_decls = H.create (List.length functions + 1000) in
(* AST.expr type to LLVM type conversion *)
let ltype_of_typ = function
A.Int -> i32_t
| A.Double -> double_t
| A.String -> str_t (* pointer to store string *)
| A.Bool -> i1_t
| A.Void -> void_t
| A.Matrix -> matrix_t
| _ -> failwith("Compiler error : ltype_of_typ function matching error.")
in
let type_of_lltype typ =
let ltype_string = L.string_of_lltype typ in
match ltype_string with
"void" -> A.Void
| "i32" -> A.Int
| "double" -> A.Double
| "i1" -> A.Bool
| "i8*" -> A.String
| "%matrix_t*" -> A.Matrix
| _ -> failwith("Compiler error : type_of_lltype function matching error.")
in
let typ_of_lvalue lv =
let lltype = L.type_of lv in
type_of_lltype lltype
in
let is_matrix ptr =
let ltype_string = L.string_of_lltype (L.type_of ptr) in
match ltype_string with
"%matrix_t*" -> true
| _ -> false
in
(* currently not used
(* LLVM value to its corresponding AST.expr Literal type conversion *)
let lit_of_lvalue lv =
let ltype = L.type_of lv in
let ltype_string = L.string_of_lltype ltype in
let lvalue = L.string_of_llvalue lv in
let type_len = String.length ltype_string in
let num_retrieve converter = converter (Str.string_after lvalue (Str.search_forward (Str.regexp "-?[0-9]+\\(\\.[0-9]*e[+-][0-9][0-9]\\)?") lvalue type_len))
and bool_retrieve converter = converter (Str.string_after lvalue (Str.search_forward (Str.regexp "[a-zA-Z]+") lvalue type_len))
and str_retrieve converter = let size =
let beg_ind = Str.search_forward (Str.regexp "[0-9]+") ltype_string 0 in
let end_ind = match_end() in
int_of_string (String.sub ltype_string beg_ind (end_ind-beg_ind))
in
let beg_ind = (Str.search_forward (Str.regexp "\".*\"") lvalue 0)+1 in
converter (String.sub lvalue beg_ind (size-1))
in
let string_identity s = s in (* some auxiliary function return a string itself *)
match ltype_string with
"i32" -> IntLit(num_retrieve int_of_string)
| "double" -> DoubleLit(num_retrieve float_of_string)
| "i1" -> BoolLit(bool_retrieve bool_of_string)
| _ -> if Str.string_match (Str.regexp "\\[[0-9]+ x i8\\]*") ltype_string 0 then StringLit(str_retrieve string_identity)
else if Str.string_match (Str.regexp "\\[[0-9]+ x \\[[0-9]+ x double\\]\\]") ltype_string 0
then if Str.string_match (Str.regexp "\\[[0-9]+ x \\[[0-9]+ x double\\]\\] zeroinitializer") lvalue 0 then MatrixLit([||], (0,0))
else let beg_ind = Str.search_forward (Str.regexp "[0-9]+") ltype_string 0 in
let end_ind = match_end() in
let r = int_of_string (String.sub ltype_string beg_ind (end_ind-beg_ind)) in
let beg_ind = Str.search_forward (Str.regexp "[0-9]+") ltype_string end_ind in
let end_ind = match_end() in
let c = int_of_string (String.sub ltype_string beg_ind (end_ind-beg_ind)) in
let mat = String.sub lvalue type_len ((String.length lvalue) - 1 - type_len) in
Bytes.set mat 0 ','; Bytes.set mat 1 ' ';
let llvm_rows = Array.of_list (Str.split (Str.regexp ", \\[[0-9]+ x double\\] ") mat) in
let build_row l llvm_row =
let beg_ind = ref 0
and end_ind = ref 0 in
try for i = 0 to (c-1) do beg_ind := Str.search_forward (Str.regexp "-?[0-9]+\\(\\.[0-9]*e[+-][0-9][0-9]\\)?") llvm_row !end_ind; end_ind := match_end();
l.(i) <- float_of_string (String.sub llvm_row !beg_ind (!end_ind - !beg_ind)) done; l
with Not_found -> l
in
let add_row m llvm_row = Array.append m [|build_row (Array.make c 0.) llvm_row|] in
MatrixLit(Array.fold_left add_row [||] llvm_rows, (r,c))
else Bug
in
*)
(* Declare printf(), which the print built-in function will call *)
let printf_t = L.var_arg_function_type i32_t [| L.pointer_type i8_t |] in
let printf_func = L.declare_function "printf" printf_t the_module in
(* use to interrupt the function flow and throw run-time exception *)
let abort_func = L.declare_function "abort" (L.function_type void_t [||]) the_module in
(* Invoke "f builder" if the current block doesn't already
have a terminal (e.g., a branch). *)
let add_terminal builder f =
match L.block_terminator (L.insertion_block !builder) with (* block terminator is one of the following in a block : ret, br, switch, indirectbr, invoke, unwind, unreachable*)
Some _ -> () (* Some a ocaml construct matching with a not null set, None match a null set *)
| None -> ignore (f !builder)
in
(* format strings *)
let string_format_str = L.build_global_stringptr "%s" "fmt_str" !main_builder in
let double_format_str = L.build_global_stringptr "%f" "fmt_double" !main_builder in
let int_format_str = L.build_global_stringptr "%d" "fmt_int" !main_builder in
let new_line_str = L.build_global_stringptr "\n" "fmt_str" !main_builder in
let two_space_str = L.build_global_stringptr " " "fmt_str" !main_builder in
let empty_str = L.build_global_stringptr "" "fmt_str" !main_builder in
let true_str = L.build_global_stringptr "true" "fmt_str" !main_builder in
let false_str = L.build_global_stringptr "false" "fmt_str" !main_builder in
let mat_dim_err_str = L.build_global_stringptr "Semantic error : wrong dimension of operands of matrix operation." "fmt_str" !main_builder in
let mat_bound_err_str = L.build_global_stringptr "Semantic error : matrix index out of bounds." "fmt_str" !main_builder in
let mat_assign_err_str = L.build_global_stringptr "Semantic error : matrix block assignment must have agreeable dimension on both sides." "fmt_str" !main_builder in
(* following function builds llvm control flow *)
(* llvm if *)
let llvm_if function_ptr builder (predicate, then_stmt, else_stmt) =
let merge_bb = L.append_block context "merge" function_ptr in (* "merge" is something like an entry, so are the rest *)
let then_bb = L.append_block context "then" function_ptr in
let then_builder = ref (L.builder_at_end context then_bb) in
add_terminal (then_stmt then_builder) (L.build_br merge_bb); (* L.build_br syntax : br entry *)
let else_bb = L.append_block context "else" function_ptr in
let else_builder = ref (L.builder_at_end context else_bb) in
add_terminal (else_stmt else_builder) (L.build_br merge_bb);
let bool_val = predicate builder in
ignore (L.build_cond_br bool_val then_bb else_bb !builder); (* L.build_cond_br syntax : br bool entry1 entry2 *)
let merge_builder = ref (L.builder_at_end context merge_bb) in
builder := !merge_builder; merge_builder
in
(* llvm while *)
let llvm_while function_ptr builder (predicate, body_stmt) =
let pred_bb = L.append_block context "while" function_ptr in
let pred_builder = ref (L.builder_at_end context pred_bb) in
ignore (L.build_br pred_bb !builder);
let body_bb = L.append_block context "while_body" function_ptr in
let body_builder = ref (L.builder_at_end context body_bb) in
add_terminal (body_stmt body_builder)
(L.build_br pred_bb);
let merge_bb = L.append_block context "merge" function_ptr in
let bool_var = predicate pred_builder in
ignore (L.build_cond_br bool_var body_bb merge_bb !pred_builder);
let merge_builder = ref (L.builder_at_end context merge_bb) in
builder := !merge_builder; merge_builder
in
(* llvm for *)
let llvm_for function_ptr builder (init, predicate, update, body_stmt) =
ignore(init builder);
let combined_stmt builder = body_stmt builder; update builder in
llvm_while function_ptr builder (predicate, combined_stmt)
in
(* matrix auxiliaries *)
(* access an entries in a matrix *)
let access mat r c x y builder =
ignore(r); (* no use but suppress warning *)
let index = L.build_add y (L.build_mul c x "tmp" !builder) "index" !builder in
L.build_gep mat [|index|] "element_ptr" !builder
in
(* matrix literal building helper *)
let build_mat_lit (v, (r,c)) builder=
let mat = L.build_array_alloca double_t (L.const_int i32_t (r*c)) "system_mat" !builder in
(for i = 0 to (r-1) do
for j = 0 to (c-1) do
let element_ptr = access mat (L.const_int i32_t r) (L.const_int i32_t c) (L.const_int i32_t i) (L.const_int i32_t j) builder in
ignore(L.build_store (L.const_float double_t v.(i).(j)) element_ptr !builder)
done
done);
let m = L.build_alloca matrix_t "m" !builder in
let m_mat = L.build_struct_gep m 0 "m_mat" !builder in
ignore(L.build_store mat m_mat !builder);
let m_r = L.build_struct_gep m 1 "m_r" !builder in
ignore(L.build_store (L.const_int i32_t r) m_r !builder);
let m_c = L.build_struct_gep m 2 "m_c" !builder in
ignore(L.build_store (L.const_int i32_t c) m_c !builder); m
in
(* create a matrix of size r by c (where r c are llvalues) *)
let build_mat_init alloc_func array_alloc_func r c function_ptr builder =
let size = L.build_mul r c "size" !builder in
let mat = array_alloc_func double_t size "system_mat" !builder in
let m = alloc_func matrix_t "m" !builder in
let m_mat = L.build_struct_gep m 0 "m_mat" !builder in
ignore(L.build_store mat m_mat !builder);
let m_r = L.build_struct_gep m 1 "m_r" !builder in
ignore(L.build_store r m_r !builder);
let m_c = L.build_struct_gep m 2 "m_c" !builder in
ignore(L.build_store c m_c !builder);
let r_high = L.build_sub r (L.const_int i32_t 1) "tmp" !builder in
let c_high = L.build_sub c (L.const_int i32_t 1) "tmp" !builder in
(*IMPORTANT: initialize to 0, otherwise it will start with some garbage value, and therefore give wrong results.*)
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let mat_element_ptr = access mat r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
ignore(L.build_store (L.const_float double_t 0.0) mat_element_ptr !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i));m
in
let stack_build_mat_init r c function_ptr builder =
build_mat_init L.build_alloca L.build_array_alloca r c function_ptr builder in
let heap_build_mat_init r c function_ptr builder =
build_mat_init L.build_malloc L.build_array_malloc r c function_ptr builder in
(* assign an array to an array on the stack *)
let mat_assign m_mat x_low x_high y_low y_high v_mat v_x_low v_y_low function_ptr builder =
let mat = L.build_load (L.build_struct_gep m_mat 0 "m_mat" !builder) "mat_mat" !builder in
let r_mat = L.build_load (L.build_struct_gep m_mat 1 "m_r" !builder) "r_mat" !builder in
let c_mat = L.build_load (L.build_struct_gep m_mat 2 "m_c" !builder) "c_mat" !builder in
let v = L.build_load (L.build_struct_gep v_mat 0 "m_mat" !builder) "mat_v" !builder in
let r_v = L.build_load (L.build_struct_gep v_mat 1 "m_r" !builder) "r_v" !builder in
let c_v = L.build_load (L.build_struct_gep v_mat 2 "m_c" !builder) "c_v" !builder in
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store x_low i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) x_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store y_low j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) y_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let mat_element_ptr = access mat r_mat c_mat (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let v_element_ptr = access v r_v c_v (L.build_add (L.build_sub (L.build_load i "i_v" !builder) x_low "tmp" !builder) v_x_low "tmp" !builder)
(L.build_add (L.build_sub (L.build_load j "j_v" !builder) y_low "tmp" !builder) v_y_low "tmp" !builder) builder in
let tmp_element = L.build_load v_element_ptr "tmp_element" !builder in
ignore(L.build_store tmp_element mat_element_ptr !builder) in
llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j) in
llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i)
in
(* print an array *)
let mat_print m_mat function_ptr builder=
let mat = L.build_load (L.build_struct_gep m_mat 0 "m_mat" !builder) "mat_mat" !builder in
let r_mat = L.build_load (L.build_struct_gep m_mat 1 "m_r" !builder) "r_mat" !builder in
let c_mat = L.build_load (L.build_struct_gep m_mat 2 "m_c" !builder) "c_mat" !builder in
let r'_mat = L.build_sub r_mat (L.const_int i32_t 1) "tmp" !builder in
let c'_mat = L.build_sub c_mat (L.const_int i32_t 1) "tmp" !builder in
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r'_mat "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c'_mat "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let mat_element_ptr = access mat r_mat c_mat (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let tmp_element = L.build_load mat_element_ptr "tmp_element" !builder in
ignore(L.build_call printf_func [| double_format_str ; tmp_element|] "printf" !builder);
ignore(L.build_call printf_func [| string_format_str ; two_space_str |] "printf" !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j));
ignore(L.build_call printf_func [| string_format_str ; new_line_str |] "printf" !builder) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i));
L.build_call printf_func [| string_format_str ; empty_str |] "printf" !builder
in
(* matrix matrix element wise operation *)
let mat_mat_element_wise m1_mat m2_mat operator function_ptr builder=
let m1 = L.build_load (L.build_struct_gep m1_mat 0 "m_mat" !builder) "mat_mat" !builder in
let r = L.build_load (L.build_struct_gep m1_mat 1 "m_r" !builder) "r_mat" !builder in
let r_high = L.build_sub r (L.const_int i32_t 1) "tmp" !builder in
let c = L.build_load (L.build_struct_gep m1_mat 2 "m_c" !builder) "c_mat" !builder in
let c_high = L.build_sub c (L.const_int i32_t 1) "tmp" !builder in
let m2 = L.build_load (L.build_struct_gep m2_mat 0 "m_mat" !builder) "mat_v" !builder in
let result_mat = stack_build_mat_init r c function_ptr builder in
let result = L.build_load (L.build_struct_gep result_mat 0 "m_mat" !builder) "mat_mat" !builder in
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let m1_element_ptr = access m1 r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m1_element = L.build_load m1_element_ptr "tmp_element" !builder in
let m2_element_ptr = access m2 r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m2_element = L.build_load m2_element_ptr "tmp_element" !builder in
let result_element_ptr = access result r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let tmp_element = operator m1_element m2_element "tmp_element" !builder in
ignore(L.build_store tmp_element result_element_ptr !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i)); result_mat
in
(*matrix equality *)
let mat_equal m1_mat m2_mat function_ptr builder=
let m1 = L.build_load (L.build_struct_gep m1_mat 0 "m_mat" !builder) "mat_mat" !builder in
let r = L.build_load (L.build_struct_gep m1_mat 1 "m_r" !builder) "r_mat" !builder in
let r_high = L.build_sub r (L.const_int i32_t 1) "tmp" !builder in
let c = L.build_load (L.build_struct_gep m1_mat 2 "m_c" !builder) "c_mat" !builder in
let c_high = L.build_sub c (L.const_int i32_t 1) "tmp" !builder in
let m2 = L.build_load (L.build_struct_gep m2_mat 0 "m_mat" !builder) "mat_v" !builder in
let result = L.build_alloca i1_t "result" !builder in
ignore(L.build_store (L.const_int i1_t 1) result !builder);
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let m1_element_ptr = access m1 r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m1_element = L.build_load m1_element_ptr "tmp_element" !builder in
let m2_element_ptr = access m2 r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m2_element = L.build_load m2_element_ptr "tmp_element" !builder in
let predicate builder = L.build_fcmp L.Fcmp.One m1_element m2_element "tmp" !builder in
let then_stmt builder = ignore(L.build_store (L.const_int i1_t 0) result !builder); builder in
let else_stmt builder = builder in
ignore(llvm_if function_ptr builder (predicate, then_stmt, else_stmt)) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i));
L.build_load result "result" !builder
in
let mat_not_equal m1_mat m2_mat function_ptr builder=
let result = L.build_alloca i1_t "result" !builder in
let tmp = mat_equal m1_mat m2_mat function_ptr builder in
let predicate builder = L.build_icmp L.Icmp.Ne tmp (L.const_int i1_t 1) "tmp" !builder in
let then_stmt builder = ignore(L.build_store (L.const_int i1_t 1) result !builder); builder in
let else_stmt builder = ignore(L.build_store (L.const_int i1_t 0) result !builder); builder in
ignore(llvm_if function_ptr builder (predicate, then_stmt, else_stmt));
L.build_load result "result" !builder
in
(* matrix number element wise operation *)
let mat_num_element_wise m1_mat num operator function_ptr builder=
let m1 = L.build_load (L.build_struct_gep m1_mat 0 "m_mat" !builder) "mat_mat" !builder in
let r = L.build_load (L.build_struct_gep m1_mat 1 "m_r" !builder) "r_mat" !builder in
let r_high = L.build_sub r (L.const_int i32_t 1) "tmp" !builder in
let c = L.build_load (L.build_struct_gep m1_mat 2 "m_c" !builder) "c_mat" !builder in
let c_high = L.build_sub c (L.const_int i32_t 1) "tmp" !builder in
let result_mat = stack_build_mat_init r c function_ptr builder in
let result = L.build_load (L.build_struct_gep result_mat 0 "m_mat" !builder) "mat_mat" !builder in
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let m1_element_ptr = access m1 r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m1_element = L.build_load m1_element_ptr "tmp_element" !builder in
let result_element_ptr = access result r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let tmp_element = operator m1_element num "tmp_element" !builder in
ignore(L.build_store tmp_element result_element_ptr !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i)); result_mat
in
(*matrix product*)
let mat_mat_product m1_mat m2_mat function_ptr builder=
let m1 = L.build_load (L.build_struct_gep m1_mat 0 "m_mat" !builder) "mat_mat" !builder in
let m2 = L.build_load (L.build_struct_gep m2_mat 0 "m_mat" !builder) "mat_v" !builder in
let r = L.build_load (L.build_struct_gep m1_mat 1 "m_r" !builder) "r_mat" !builder in
let r_high = L.build_sub r (L.const_int i32_t 1) "tmp" !builder in
let c = L.build_load (L.build_struct_gep m2_mat 2 "m_c" !builder) "c_mat" !builder in
let c_high = L.build_sub c (L.const_int i32_t 1) "tmp" !builder in
let l = L.build_load (L.build_struct_gep m1_mat 2 "m_l" !builder) "l_mat" !builder in
let l_high = L.build_sub l (L.const_int i32_t 1) "tmp" !builder in
let result_mat = stack_build_mat_init r c function_ptr builder in
let result = L.build_load (L.build_struct_gep result_mat 0 "m_mat" !builder) "mat_mat" !builder in
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let result_element_ptr = access result r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let tmp_element = L.build_alloca double_t "tmp_element" !builder in
ignore(L.build_store (L.const_float double_t 0.0) tmp_element !builder); (*IMPORTANT: initialize to 0, otherwise it will start with some garbage value, and therefore give wrong results.*)
let k = L.build_alloca i32_t "k" !builder in
let init_k builder = L.build_store (L.const_int i32_t 0) k !builder in
let predicate_k builder = L.build_icmp L.Icmp.Sle (L.build_load k "k_v" !builder) l_high "bool_val" !builder in
let update_k builder = ignore(L.build_store (L.build_add (L.build_load k "k_v" !builder) (L.const_int i32_t 1) "tmp" !builder) k !builder);builder in
let body_stmt_k builder =
let m1_element_ptr = access m1 r l (L.build_load i "i_v" !builder) (L.build_load k "k_v" !builder) builder in
let m1_element = L.build_load m1_element_ptr "tmp_element" !builder in
let m2_element_ptr = access m2 l c (L.build_load k "k_v" !builder) (L.build_load j "j_v" !builder) builder in
let m2_element = L.build_load m2_element_ptr "tmp_element" !builder in
ignore(L.build_store (L.build_fadd (L.build_fmul m1_element m2_element "tmp" !builder) (L.build_load tmp_element "tmp" !builder) "tmp" !builder) tmp_element !builder) in
ignore(llvm_for function_ptr builder (init_k, predicate_k, update_k, body_stmt_k));
ignore(L.build_store (L.build_load tmp_element "tmp" !builder) result_element_ptr !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i)); result_mat
in
(* rgb array to rgb matrix *)
let to_rgb_matrix mat_arr mat_r mat_g mat_b r c function_ptr builder =
let m_r = L.build_load (L.build_struct_gep mat_r 0 "mat_r" !builder) "mat_mat" !builder in
let m_g = L.build_load (L.build_struct_gep mat_g 0 "mat_g" !builder) "mat_mat" !builder in
let m_b = L.build_load (L.build_struct_gep mat_b 0 "mat_b" !builder) "mat_mat" !builder in
let r_high = L.build_sub r (L.const_int i32_t 1) "tmp" !builder in
let c_high = L.build_sub c (L.const_int i32_t 1) "tmp" !builder in
let counter = L.build_alloca i32_t "counter" !builder in
ignore(L.build_store (L.const_int i32_t 2) counter !builder);
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let m_r_element_ptr = access m_r r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m_g_element_ptr = access m_g r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m_b_element_ptr = access m_b r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
ignore(L.build_store (L.build_load (L.build_gep mat_arr [|(L.build_load counter "counter" !builder)|] "element_ptr" !builder) "tmp_element" !builder) m_b_element_ptr !builder);
let tmp = L.build_add (L.build_load counter "counter" !builder) (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store tmp counter !builder);
ignore(L.build_store (L.build_load (L.build_gep mat_arr [|(L.build_load counter "counter" !builder)|] "element_ptr" !builder) "tmp_element" !builder) m_g_element_ptr !builder);
let tmp = L.build_add (L.build_load counter "counter" !builder) (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store tmp counter !builder);
ignore(L.build_store (L.build_load (L.build_gep mat_arr [|(L.build_load counter "counter" !builder)|] "element_ptr" !builder) "tmp_element" !builder) m_r_element_ptr !builder);
let tmp = L.build_add (L.build_load counter "counter" !builder) (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store tmp counter !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i))
in
(* rgb matrix to rgb array *)
let from_rgb_matrix mat_arr mat_r mat_g mat_b r c function_ptr builder =
let m_r = L.build_load (L.build_struct_gep mat_r 0 "mat_r" !builder) "mat_mat" !builder in
let m_g = L.build_load (L.build_struct_gep mat_g 0 "mat_g" !builder) "mat_mat" !builder in
let m_b = L.build_load (L.build_struct_gep mat_b 0 "mat_b" !builder) "mat_mat" !builder in
let r_high = L.build_sub r (L.const_int i32_t 1) "tmp" !builder in
let c_high = L.build_sub c (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store (L.build_sitofp r double_t "tmp" !builder) (L.build_gep mat_arr [|(L.const_int i32_t 0)|] "element_ptr" !builder) !builder);
ignore(L.build_store (L.build_sitofp c double_t "tmp" !builder) (L.build_gep mat_arr [|(L.const_int i32_t 1)|] "element_ptr" !builder) !builder);
let counter = L.build_alloca i32_t "counter" !builder in
ignore(L.build_store (L.const_int i32_t 2) counter !builder);
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) r_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) c_high "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let m_r_element_ptr = access m_r r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m_g_element_ptr = access m_g r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
let m_b_element_ptr = access m_b r c (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
ignore(L.build_store (L.build_load m_b_element_ptr "tmp_element" !builder) (L.build_gep mat_arr [|(L.build_load counter "counter" !builder)|] "element_ptr" !builder) !builder);
let tmp = L.build_add (L.build_load counter "counter" !builder) (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store tmp counter !builder);
ignore(L.build_store (L.build_load m_g_element_ptr "tmp_element" !builder) (L.build_gep mat_arr [|(L.build_load counter "counter" !builder)|] "element_ptr" !builder) !builder);
let tmp = L.build_add (L.build_load counter "counter" !builder) (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store tmp counter !builder);
ignore(L.build_store (L.build_load m_r_element_ptr "tmp_element" !builder) (L.build_gep mat_arr [|(L.build_load counter "counter" !builder)|] "element_ptr" !builder) !builder);
let tmp = L.build_add (L.build_load counter "counter" !builder) (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store tmp counter !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i))
in
(* face array to face matrix *)
let face_matrix mat_arr mat num function_ptr builder =
let m = L.build_load (L.build_struct_gep mat 0 "mat_r" !builder) "mat_mat" !builder in
let counter = L.build_alloca i32_t "counter" !builder in
ignore(L.build_store (L.const_int i32_t 1) counter !builder);
let num_high = L.build_sub num (L.const_int i32_t 1) "tmp" !builder in
let i = L.build_alloca i32_t "i" !builder in
let init_i builder = L.build_store (L.const_int i32_t 0) i !builder in
let predicate_i builder = L.build_icmp L.Icmp.Sle (L.build_load i "i_v" !builder) num_high "bool_val" !builder in
let update_i builder = ignore(L.build_store (L.build_add (L.build_load i "i_v" !builder) (L.const_int i32_t 1) "tmp" !builder) i !builder);builder in
let body_stmt_i builder =
let j = L.build_alloca i32_t "j" !builder in
let init_j builder = L.build_store (L.const_int i32_t 0) j !builder in
let predicate_j builder = L.build_icmp L.Icmp.Sle (L.build_load j "j_v" !builder) (L.const_int i32_t 3) "bool_val" !builder in
let update_j builder = ignore(L.build_store (L.build_add (L.build_load j "j_v" !builder) (L.const_int i32_t 1) "tmp" !builder) j !builder);builder in
let body_stmt_j builder =
let m_element_ptr = access m (L.const_int i32_t 4) num (L.build_load i "i_v" !builder) (L.build_load j "j_v" !builder) builder in
ignore(L.build_store (L.build_load (L.build_gep mat_arr [|(L.build_load counter "counter" !builder)|] "element_ptr" !builder) "tmp_element" !builder) m_element_ptr !builder);
let tmp = L.build_add (L.build_load counter "counter" !builder) (L.const_int i32_t 1) "tmp" !builder in
ignore(L.build_store tmp counter !builder) in
ignore(llvm_for function_ptr builder (init_j, predicate_j, update_j, body_stmt_j)) in
ignore(llvm_for function_ptr builder (init_i, predicate_i, update_i, body_stmt_i))
in
(* 2. Statement construction *)
(* part of code for generating statement, which used both in main function and function definition *)
let rec build_stmt (fdecl, function_ptr) local_vars builder stmt current_return=
(* Return the value for a variable or formal argument *)
let rec expr builder e=
(*expr builder e auxiliaries *)
let return_aux e t =
match t with
A.Matrix ->
let m = L.build_load (L.build_struct_gep e 0 "m_mat" !builder) "mat_mat" !builder in
let r = L.build_load (L.build_struct_gep e 1 "m_r" !builder) "r_mat" !builder in
let c = L.build_load (L.build_struct_gep e 2 "m_c" !builder) "c_mat" !builder in
let mat = stack_build_mat_init r c function_ptr builder in
ignore(mat_assign mat (L.const_int i32_t 0) (L.build_sub r (L.const_int i32_t 1) "tmp" !builder)
(L.const_int i32_t 0) (L.build_sub c (L.const_int i32_t 1) "tmp" !builder)
e (L.const_int i32_t 0) (L.const_int i32_t 0) function_ptr builder);
ignore(L.build_free m !builder); ignore(L.build_free e !builder);mat
| _ -> e
in
let rec lookup n access=
match access with
Access(prev_access, map) ->
(try (H.find map n, map)
with Not_found -> lookup n prev_access)
| Null -> failwith("Semantic error : variable " ^ n ^ " not declared")
in
(* convert A.index type to corresponding integral index in a matrix of size r by c *)
(* for run time dimension check on matrix *)
let run_time_property_check function_ptr builder err_msg v1 op v2 else_stmt =
let predicate builder= op v1 v2 "tmp" !builder in
let then_stmt builder = ignore(L.build_call printf_func [| string_format_str ; err_msg |] "printf" !builder);
ignore(L.build_call abort_func [| |] "" !builder); builder in
llvm_if function_ptr builder (predicate, then_stmt, else_stmt)
in
let run_time_dim_check function_ptr builder v1 op v2 else_stmt =
run_time_property_check function_ptr builder mat_dim_err_str v1 op v2 else_stmt
in
let index_converter d ind r c builder=
match ind with
A.Beg -> L.const_int i32_t 0
| A.End -> (match d with
"x" -> L.build_sub r (L.const_int i32_t 1) "tmp" !builder
| "y" -> L.build_sub c (L.const_int i32_t 1) "tmp" !builder
| _ -> failwith ("Compiler error : index_converter wrong dimension symbol. "))
| A.ExprInd(e) -> let e' = expr builder e in
if (L.string_of_lltype (L.type_of e')) <> "i32" then failwith ("Semantic error : matrix index must be integer.");
let else_stmt builder = builder in
(match d with
"x" -> ignore(run_time_property_check function_ptr builder mat_bound_err_str (L.const_int i32_t 0) (L.build_icmp L.Icmp.Sgt) e' else_stmt);
ignore(run_time_property_check function_ptr builder mat_bound_err_str (L.build_sub r (L.const_int i32_t 1) "tmp" !builder) (L.build_icmp L.Icmp.Slt) e' else_stmt);
| "y" -> ignore(run_time_property_check function_ptr builder mat_bound_err_str (L.const_int i32_t 0) (L.build_icmp L.Icmp.Sgt) e' else_stmt);
ignore(run_time_property_check function_ptr builder mat_bound_err_str (L.build_sub c (L.const_int i32_t 1) "tmp" !builder) (L.build_icmp L.Icmp.Slt) e' else_stmt);
| _ -> failwith ("Compiler error : index_converter wrong dimension symbol. ")); e'
in
match e with
A.IntLit i -> L.const_int i32_t i
| A.DoubleLit d -> L.const_float double_t d
| A.StringLit s -> L.build_global_stringptr s "system_string" !builder
| A.BoolLit b -> L.const_int i1_t (if b then 1 else 0)
| A.MatrixLit (m, (r, c)) -> build_mat_lit (m, (r,c)) builder(* matrix is represented as arrays of arrays of double in LLVM *)
| A.Noexpr -> L.const_int i32_t 0
| A.Noassign -> L.const_int i32_t 0
| A.Id s ->
let ptr,_ = lookup s local_vars in
(match (is_matrix ptr) with
true -> ptr
| false -> L.build_load ptr s !builder)
| A.Binop (e1, op, e2) ->
let exp1 = expr builder e1
and exp2 = expr builder e2 in
(match (is_matrix exp1, is_matrix exp2) with
(false, false)->
(let typ1 = L.string_of_lltype (L.type_of exp1)
and typ2 = L.string_of_lltype (L.type_of exp2) in
(match (typ1, typ2) with
("i1", "i1") -> (match op with
A.And -> L.build_and
| A.Or -> L.build_or
| A.Equal -> L.build_icmp L.Icmp.Eq
| A.Neq -> L.build_icmp L.Icmp.Ne
| _ -> failwith("Semantic error : wrong operator used on boolean operands.")
) exp1 exp2 "tmp" !builder
| ("double", "double") | ("i32", "i32") | ("double", "i32") | ("i32", "double") ->
let build_op_by_type opf opi =
(match (typ1, typ2) with
("double", "double") -> opf
| ("i32", "i32") -> opi
| ("double", "i32") ->
(fun e1 e2 n bdr -> let e2' = L.build_sitofp e2 double_t n bdr in
opf e1 e2' "tmp" bdr)
| ("i32", "double") ->
(fun e1 e2 n bdr -> let e1' = L.build_sitofp e1 double_t n bdr in
opf e1' e2 "tmp" bdr)
| _ -> failwith ("Compiler error : numerical operation matching error at build_op_by_type.") )
in
(match op with
A.Add -> build_op_by_type L.build_fadd L.build_add
| A.Sub -> build_op_by_type L.build_fsub L.build_sub
| A.Mult -> build_op_by_type L.build_fmul L.build_mul
| A.Div -> build_op_by_type L.build_fdiv L.build_sdiv
| A.Rmdr -> build_op_by_type L.build_frem L.build_srem
| A.Equal -> build_op_by_type (L.build_fcmp L.Fcmp.Oeq) (L.build_icmp L.Icmp.Eq)
| A.Neq -> build_op_by_type (L.build_fcmp L.Fcmp.One) (L.build_icmp L.Icmp.Ne)
| A.Less -> build_op_by_type (L.build_fcmp L.Fcmp.Olt) (L.build_icmp L.Icmp.Slt)
| A.Leq -> build_op_by_type (L.build_fcmp L.Fcmp.Ole) (L.build_icmp L.Icmp.Sle)
| A.Greater -> build_op_by_type (L.build_fcmp L.Fcmp.Ogt) (L.build_icmp L.Icmp.Sgt)
| A.Geq -> build_op_by_type (L.build_fcmp L.Fcmp.Oge) (L.build_icmp L.Icmp.Sge)
| _ -> failwith ("Semantic error : wrong operator used on numerical operands.")
) exp1 exp2 "tmp" !builder
| _ -> failwith ("semantic error : invalid numerical operation between type " ^ typ1 ^ " and " ^ typ2)))
(* matrix operation *)
| (true, false) | (false, true) ->
let operator =
(match op with
A.Add -> L.build_fadd
| A.Sub -> L.build_fsub
| A.Mult -> L.build_fmul
| A.Div -> L.build_fdiv
| _ -> failwith ("Semantic error : wrong operator used on matrix non-matrix operation.")
)
in
(match (is_matrix exp1, is_matrix exp2) with
| (true, false) -> let typ2 = L.string_of_lltype (L.type_of exp2) in
(match typ2 with
"double" -> mat_num_element_wise exp1 exp2 operator function_ptr builder
| _ -> failwith("Semantic error : invalid numerical operation between type matrix and "^ typ2))
| (false, true) -> let typ1 = L.string_of_lltype (L.type_of exp1) in
(match typ1 with
"double" -> mat_num_element_wise exp2 exp1 operator function_ptr builder
| _ -> failwith("Semantic error : invalid numerical operation between type " ^ typ1 ^ " and matrix."))
| _ -> failwith("Compiler error : Binop operator matching error."))
| (true, true) ->
(match op with
A.Filter -> expr builder (A.Call("filter",[e1; e2]))
| A.Matprod ->
let j1 = L.build_load (L.build_struct_gep exp1 2 "m_c" !builder) "c_mat" !builder in
let i2 = L.build_load (L.build_struct_gep exp2 1 "m_r" !builder) "r_mat" !builder in
let else_stmt builder= builder in
ignore(run_time_dim_check function_ptr builder j1 (L.build_icmp L.Icmp.Ne) i2 else_stmt);
mat_mat_product exp1 exp2 function_ptr builder
| _ ->
let i1 = L.build_load (L.build_struct_gep exp1 1 "m_r" !builder) "r_mat" !builder in
let i2 = L.build_load (L.build_struct_gep exp2 1 "m_r" !builder) "r_mat" !builder in
let else_stmt builder =
let j1 = L.build_load (L.build_struct_gep exp1 2 "m_c" !builder) "c_mat" !builder in
let j2 = L.build_load (L.build_struct_gep exp2 2 "m_c" !builder) "c_mat" !builder in
let else_stmt builder =
builder
in
run_time_dim_check function_ptr builder j1 (L.build_icmp L.Icmp.Ne) j2 else_stmt
in
ignore(run_time_dim_check function_ptr builder i1 (L.build_icmp L.Icmp.Ne) i2 else_stmt);
(match op with
A.Equal -> mat_equal exp1 exp2 function_ptr builder
| A.Neq -> mat_not_equal exp1 exp2 function_ptr builder
| A.Add -> mat_mat_element_wise exp1 exp2 L.build_fadd function_ptr builder
| A.Sub -> mat_mat_element_wise exp1 exp2 L.build_fsub function_ptr builder
| A.Mult -> mat_mat_element_wise exp1 exp2 L.build_fmul function_ptr builder
| A.Div -> mat_mat_element_wise exp1 exp2 L.build_fdiv function_ptr builder
| _ -> failwith ("Semantic error : wrong operator used on matrix operation.")) ))
| A.Unop(op, e) ->
let e' = expr builder e in
let typ = L.string_of_lltype (L.type_of e') in
(match op with
A.Neg ->
(match typ with
"i32" -> L.build_neg
| "double" -> L.build_fneg
| _ -> failwith ("Semantic error : wrong operands for unary negation operator."))
| A.Not when typ = "i1"-> L.build_not
| _ -> failwith ("Semantic error : illegal unary operation.") )e' "tmp" !builder
| A.Assign (e1, e2) ->
let single_assign e1 value =
(match e1 with
A.Id s ->
let ptr,map = lookup s local_vars in
(match (is_matrix ptr) with
true ->
if (L.string_of_lltype (L.type_of value) <> "%matrix_t*")
then failwith("Semantic error : matrix must be assigned to a matrix.");
let r = L.build_load (L.build_struct_gep value 1 "m_r" !builder) "r_mat" !builder in
let c = L.build_load (L.build_struct_gep value 2 "m_c" !builder) "c_mat" !builder in
let m = stack_build_mat_init r c function_ptr builder in
H.replace map s m;
ignore(mat_assign m (L.const_int i32_t 0) (L.build_sub r (L.const_int i32_t 1) "tmp" !builder)
(L.const_int i32_t 0) (L.build_sub c (L.const_int i32_t 1) "tmp" !builder)
value (L.const_int i32_t 0) (L.const_int i32_t 0) function_ptr builder); value
| false ->
let typ1 = L.string_of_lltype (L.type_of (L.build_load ptr "tmp" !builder)) in
let typ2 = L.string_of_lltype (L.type_of value) in
if (typ1 <> typ2) then failwith ("Semantic error : type "^typ1^" is assigned with type " ^typ2);
ignore(L.build_store value ptr !builder); value)
| A.Index (s, (A.Range(x_low, x_high), A.Range(y_low, y_high))) ->
let ptr,_ = lookup s local_vars in
let r = L.build_load (L.build_struct_gep ptr 1 "m_r" !builder) "r_mat" !builder in
let c = L.build_load (L.build_struct_gep ptr 2 "m_c" !builder) "c_mat" !builder in
let x_l = index_converter "x" x_low r c builder in
let x_h = index_converter "x" x_high r c builder in
let y_l = index_converter "y" y_low r c builder in
let y_h = index_converter "y" y_high r c builder in
if ((x_low = x_high) && (y_low = y_high))
then (
if (L.string_of_lltype (L.type_of value)) <> "double" then failwith ("Syntax error : single matrix entry must be assigned with a double");
let mat = L.build_load (L.build_struct_gep ptr 0 "mat" !builder) "mat" !builder in
L.build_store value (access mat r c x_l y_l builder) !builder)
else (
let i1 = L.build_add (L.build_sub x_h x_l "tmp" !builder) (L.const_int i32_t 1) "tmp" !builder in
let i2 = L.build_load (L.build_struct_gep value 1 "m_r" !builder) "r_mat" !builder in
ignore(run_time_property_check function_ptr builder mat_assign_err_str i1 (L.build_icmp L.Icmp.Ne) i2 (fun builder -> builder));
let j1 = L.build_add (L.build_sub y_h y_l "tmp" !builder) (L.const_int i32_t 1) "tmp" !builder in
let j2 = L.build_load (L.build_struct_gep value 2 "m_r" !builder) "r_mat" !builder in
ignore(run_time_property_check function_ptr builder mat_assign_err_str j1 (L.build_icmp L.Icmp.Ne) j2 (fun builder -> builder));
ignore(mat_assign ptr x_l x_h y_l y_h value (L.const_int i32_t 0) (L.const_int i32_t 0) function_ptr builder); value)
| _ -> failwith ("Semantic error : only variable and matrix indexing can be assigned to."))
in
let value = expr builder e2 in
(match e1 with
A.Comma s_list ->
(match e2 with
A.Call(f,_) ->
let (_, fdecl) = H.find function_decls f in
let l = match fdecl.A.typ with A.Mulret li -> li | _ -> failwith("Compiler error : Assign expr at A.Call return type is not Mulret") in
let l1 = List.length s_list in
let l2 = List.length l in
if (l1 <> l2) then failwith("Semantic error : "^string_of_int(l1)^" variables are assigned to function call "^f^" which returns "^string_of_int(l2)^" variables.");
(for i = 0 to ((List.length l) - 1) do
let v = L.build_load (L.build_struct_gep value i "v_ptr" !builder) "v" !builder in
ignore (single_assign (List.nth s_list i) (return_aux v (List.nth l i)))
done);
ignore(L.build_free value !builder);
| _ -> failwith("Syntax error: multiple variables must be assigned with a function call that has multiple return values.") ); value
| _ -> single_assign e1 value
)
| A.Index (s, (A.Range(x_low, x_high), A.Range(y_low, y_high))) ->
let ptr, _ = lookup s local_vars in
let r = L.build_load (L.build_struct_gep ptr 1 "m_r" !builder) "r_mat" !builder in
let c = L.build_load (L.build_struct_gep ptr 2 "m_c" !builder) "c_mat" !builder in
let x_l = index_converter "x" x_low r c builder in
let x_h = index_converter "x" x_high r c builder in
let y_l = index_converter "y" y_low r c builder in
let y_h = index_converter "y" y_high r c builder in
if ((x_low = x_high) && (y_low = y_high))
then (
let mat = L.build_load (L.build_struct_gep ptr 0 "mat" !builder) "mat" !builder in
L.build_load (access mat r c x_l y_l builder) "element" !builder)
else (
let x_size = L.build_sub x_h x_l "tmp" !builder in
let y_size = L.build_sub y_h y_l "tmp" !builder in
let m = stack_build_mat_init (L.build_add x_size (L.const_int i32_t 1) "tmp" !builder)
(L.build_add y_size (L.const_int i32_t 1) "tmp" !builder) function_ptr builder in
ignore(mat_assign m (L.const_int i32_t 0) x_size (L.const_int i32_t 0) y_size ptr x_l y_l function_ptr builder); m)
(*| A.Index (s, (Range(x_low, x_high), Range(y_low, y_high))) ->
let (t,ptr) = lookup s in
let A.Sizedmat(r, c) = t in
ptr*)
| A.Call ("printf", [e]) ->
let exp1 = expr builder e in
(match (typ_of_lvalue exp1) with
A.Double -> L.build_call printf_func [| double_format_str ; (exp1) |] "printf" !builder
| A.Int -> L.build_call printf_func [| int_format_str ; (exp1) |] "printf" !builder
| A.Bool ->
let predicate builder = L.build_icmp L.Icmp.Ne (L.const_int i1_t 1) exp1 "tmp" !builder in
let then_stmt builder = ignore(L.build_call printf_func [| string_format_str ; false_str |] "printf" !builder); builder in
let else_stmt builder = ignore(L.build_call printf_func [| string_format_str ; true_str |] "printf" !builder); builder in
ignore(llvm_if function_ptr builder (predicate, then_stmt, else_stmt));
L.build_call printf_func [| string_format_str ; empty_str |] "printf" !builder
| A.Matrix -> mat_print exp1 function_ptr builder
| A.String -> L.build_call printf_func [| string_format_str ; (exp1) |] "printf" !builder
| _ -> failwith("Compiler error : unknown type expr passed to printf.")
)
| A.Call ("printend", []) ->
L.build_call printf_func [| string_format_str ; new_line_str |] "printf" !builder
| A.Call (f, act) ->
let (fdef, fdecl) =
match !current_return with
Maintype | Returnstruct(_) ->
(try H.find function_decls f with Not_found -> failwith ("Semantic error : function "^f^" not defined."))
| _ -> H.find function_decls f
in
let actuals = List.rev (List.map (expr builder) (List.rev act)) in
if (List.length actuals) <> (List.length fdecl.A.formals)
then failwith("Semantic error : expecting " ^ string_of_int (List.length fdecl.A.formals) ^ " arguments in function call "^f);
List.iter2 (fun (t, _) actual -> if typ_of_lvalue(actual) <> t
then failwith ("Semantic error : wrong type of arguments in function call "^f)) fdecl.A.formals actuals;
let result =
(match fdecl.A.typ with
A.Void -> ""
| _ -> f ^ "_result")
in
let exp = L.build_call fdef (Array.of_list actuals) result !builder in(* corresponding to call void @foo(i32 2, i32 1) *)
(match fdecl.A.typ with
A.Void -> exp
| A.Mulret l ->
(match (List.length l) with
1 -> let v = L.build_load (L.build_struct_gep exp 0 "v_ptr" !builder) "v" !builder in
ignore(L.build_free exp !builder);
return_aux v (List.hd l)
| _ -> exp)(* multi return case, can only be used in A.Assign, and we will deal with it there. *) (* there is a memory leak here due to possible multi-return funciton call without assignment, haven't got time to tie up *)
| _ -> failwith ("Compiler error : Call expr function return type neither Void nor Mulret."))
| A.Comma(_) -> failwith("Syntax error : Wrong usage of comma seperated list.")
| _ -> failwith("Syntax error : Wrong usage of matrix indexing, possible standalone indexing expressions.")
in
match stmt with
(* Build the code for the given statement; return the builder for
the statement's successor *)
A.Block sl ->
let local_vars = Access(local_vars, H.create 1000) in
let build_st st = ignore (build_stmt (fdecl, function_ptr) local_vars builder st current_return) in
List.iter build_st sl; builder
| A.Expr e -> ignore (expr builder e); builder
| A.Return e ->
(* Since we are infering return type from e, we need to consider if a funciton is recursive, and thus when we build the function return in its body, its return type has not yet been inferred, and its definition is not seen, so it cannot call itself because it cannot find itself in function_decls, but the thing is that recursive function always has a base case (i.e. a return whose return value is not recursing on itself, and that we can infer on, so we just need to find that return, and use its type as our return type *)
(let eval_return e=
let e' = expr builder e in
match (is_matrix e') with
true -> (* alloca space in heap to temporarily store the matrix struct, otherwise the matrix struct is stored in the stack of the function that is returning, so after return, the stack would be cleared, and we might have the matrix just storing garbage information. *)
let r = L.build_load (L.build_struct_gep e' 1 "m_r" !builder) "r_mat" !builder in
let c = L.build_load (L.build_struct_gep e' 2 "m_c" !builder) "c_mat" !builder in
let mat = heap_build_mat_init r c function_ptr builder in
ignore(mat_assign mat (L.const_int i32_t 0) (L.build_sub r (L.const_int i32_t 1) "tmp" !builder)
(L.const_int i32_t 0) (L.build_sub c (L.const_int i32_t 1) "tmp" !builder)
e' (L.const_int i32_t 0) (L.const_int i32_t 0) function_ptr builder);mat
| false -> e'
in
let build_return l t=
let build_return_struct l return=
for i = 0 to ((List.length l)-1) do
let e = List.nth l i in
let e' = eval_return e in
ignore(L.build_store e' (L.build_struct_gep return i ("return"^string_of_int(i)) !builder) !builder);
done
in
let return = L.build_malloc t "return" !builder in
(*L.build_store (L.const_int i32_t (List.length l)) (L.build_struct_gep return 0 "return_size" !builder) !builder;*)
build_return_struct l return;
ignore(L.build_ret return !builder)
in
match !current_return with
Maintype -> ignore(L.build_ret (L.const_int i32_t 0) !builder)
| Returnstruct t -> (* this is used to build actual function body *)
(match e with
A.Noexpr -> ignore(L.build_ret_void !builder)
| A.Comma l-> build_return l t;
| _ -> let l = [e] in build_return l t);
| Lltypearray ltyp_arr-> (* this is used for return type inference *)
(match e with
A.Noexpr -> current_return := Voidtype(void_t)
| A.Comma l ->
(match ltyp_arr with
[||] -> current_return := Lltypearray(Array.make (List.length l) void_t)
| _ -> ());
let ltyp_arr = match !current_return with Lltypearray l -> l | _ -> failwith("Compiler error : Lltypearray wrong matching.") in
for i = 0 to ((List.length l)-1) do
try let e'= expr builder (List.nth l i) in
ltyp_arr.(i) <- L.type_of e';
with Not_found -> ()
done
| _ ->
(match ltyp_arr with
[||] -> current_return := Lltypearray([|void_t|])
| _ -> ());
let ltyp_arr = match !current_return with Lltypearray l -> l | _ -> failwith("Compiler error : Lltypearray wrong matching.") in
try let e'= expr builder e in
ltyp_arr.(0) <- L.type_of e';
with Not_found -> ())
| Voidtype(_) -> ()
);builder
| A.If (predicate, then_stmt, else_stmt) ->
let cond = expr builder predicate in
if ((L.string_of_lltype (L.type_of cond)) <> "i1") then failwith ("Semantic error : predicate of if clause is not boolean.");
let pred builder = expr builder predicate in
let then_st builder = build_stmt (fdecl, function_ptr) local_vars builder then_stmt current_return in
let else_st builder = build_stmt(fdecl, function_ptr) local_vars builder else_stmt current_return in
ignore(llvm_if function_ptr builder (pred, then_st, else_st)); builder
| A.While (predicate, body) ->
let cond = expr builder predicate in
if ((L.string_of_lltype (L.type_of cond)) <> "i1") then failwith ("Semantic error : predicate of while loop is not boolean.");
let pred builder = expr builder predicate in
let body_st builder = build_stmt (fdecl, function_ptr) local_vars builder body current_return in
ignore(llvm_while function_ptr builder (pred, body_st)); builder
| A.For (e1, e2, e3, body) ->
let cond = expr builder e2 in
if ((L.string_of_lltype (L.type_of cond)) <> "i1") then failwith ("Semantic error : predicate of for loop is not boolean.");
let init_st builder = expr builder e1 in
let pred builder = expr builder e2 in
let update builder = ignore(expr builder e3); builder in
let body_st builder = build_stmt (fdecl, function_ptr) local_vars builder body current_return in
ignore(llvm_for function_ptr builder (init_st, pred, update, body_st)); builder
| A.Local (t, n, v) -> let map = match local_vars with Access(_, map) -> map | Null -> failwith("Compiler error : local access link error") in
(match t with
A.Matrix ->
(match v with
A.Noassign -> let local = stack_build_mat_init (L.const_int i32_t 0) (L.const_int i32_t 0) function_ptr builder in
H.add map n local;
| _-> let v' = expr builder v in