diff --git a/2-inline_f90_str_copy_klen.patch b/2-inline_f90_str_copy_klen.patch new file mode 100644 index 0000000000000000000000000000000000000000..3f59568a03aa1b87af218a7917939db72ae7ead8 --- /dev/null +++ b/2-inline_f90_str_copy_klen.patch @@ -0,0 +1,677 @@ +commit ba10b360a6960b0f9e1157502f33c68543e73bcb +Author: wzw <51215902151@stu.ecnu.edu.cn> +Date: Thu Sep 8 11:07:41 2022 +0800 + + [flang2] Add inline_f90_str_copy_klen to framework for inline f90-prefix + runtime call + + This patch adds a function named inline_f90_str_copy_klen to the + framework for inlining f90-prefix runtime call. This function is + an inline implementation of f90_str_copy_klen, which is for + copying and concatenation of several strings. + +diff --git a/docs/inline_f90_str_copy_klen.txt b/docs/inline_f90_str_copy_klen.txt +new file mode 100644 +index 00000000..d68a564d +--- /dev/null ++++ b/docs/inline_f90_str_copy_klen.txt +@@ -0,0 +1,73 @@ ++------------------------------ ++Introduction: ++This functionality is implemented in a frame which allows flang to inline f90-prefix runtime call before writing out the generated IR. This implementation is the inlining of the "f90_str_copy_klen" function which is used to concatenate and copy several strings to the target string. ++ ++------------------------------ ++Implementation: ++This function first traverses the generated IR instructions in flang2. If the "I_CALL" instruction is found, the called function is judged to confirm whether it is a function that can be inlined like "f90_str_copy_klen". ++When implementing the "inline_f90_str_copy_klen" function, we will use the pointer to record the address, length and character index of the target string and the input string. For each input string, if the index of the target string is less than the length value, the characters in the input string are copied to the target string in order until the current input string has been completely copied or the index of the target string is equal to length value. According to the above method, all the input strings are traversed in order. If the index of the target string is still less than the length value after the traversal is completed, the remaining characters are supplemented with spaces. We will generate the IR instruction corresponding to this method to replace the "f90_str_copy_klen" and "I_CALL" instructions to achieve inlining. ++ ++------------------------------ ++Correctness test: ++Our code tests the implementation of the function in ten cases based on the number of input strings and the length of each string: ++ 1. a = b ++ 1.1 len(a) < len(b) ++ 1.2 len(a) = len(b) ++ 1.3 len(a) > len(b) ++ 2. a = b // c // d ++ 2.1 len(a) < len(b) ++ 2.2 len(a) = len(b) ++ 2.3 len(b) < len(a) < len(b) + len(c) ++ 2.4 len(a) = len(b) + len(c) ++ 2.5 len(b) + len(c) < len(a) < len(b) + len(c) + len(d) ++ 2.6 len(a) = len(b) + len(c) + len(d) ++ 2.7 len(a) > len(b) + len(c) + len(d) ++The tested string also contains some special characters whose ASCII code is less than 32. And our tests have shown that this function can be used normally. ++ ++------------------------------ ++Performance test: ++To demonstrate the degree of optimization obtained by inlining the "f90_str_copy_klen" function, we repeated "d=a//b//c" in the function 100 million times. According to the statistical results, the running time of this function before inlining takes about 7 seconds, and after inlining optimization, the running time of this function only takes about 0.8 seconds. ++ ++! Performance test case: ++main.f90: ++program main ++ integer :: i ++ character(20) :: a, b, c, d ++ a = "aaaaaaaaaaaaaaa" ++ b = "aaaaaaaaaaaaaaa" ++ c = "aaaaaaaaaaaaaaa" ++ do i = 1, 100000000 ++ call test(a, b, c, d, 20) ++ enddo ++end ++ ++test.f90: ++subroutine test(a, b, c, d, n) ++ integer :: n ++ character(n) :: a, b, c, d ++ d = a // b // c ++end subroutine ++ ++! How to test: ++Run time before inline: ++$ flang main.f90 -c ++$ flang test.f90 -O3 -c ++$ flang test.o main.o ++$ time ./a.out ++ ++The following is the result without inline: ++real 0m7.936s ++user 0m7.880s ++sys 0m0.004s ++ ++Run time after inline: ++$ flang main.f90 -c ++$ flang test.f90 -O3 -c -Mx,218,0x1 ++$ flang test.o main.o ++$ time ./a.out ++ ++The following is the result after inline: ++real 0m0.807s ++user 0m0.807s ++sys 0m0.000s ++ +diff --git a/test/f90_correct/inc/inline_f90_str_copy_klen.mk b/test/f90_correct/inc/inline_f90_str_copy_klen.mk +new file mode 100644 +index 00000000..a2f1f193 +--- /dev/null ++++ b/test/f90_correct/inc/inline_f90_str_copy_klen.mk +@@ -0,0 +1,22 @@ ++# ++# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++# See https://llvm.org/LICENSE.txt for license information. ++# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++# ++ ++$(TEST): run ++ ++ ++build: $(SRC)/$(TEST).f90 ++ -$(RM) $(TEST).$(EXESUFFIX) core *.d *.mod FOR*.DAT FTN* ftn* fort.* ++ @echo ------------------------------------ building test $@ ++ -$(FC) -c $(FFLAGS) $(LDFLAGS) $(SRC)/$(TEST).f90 -Mx,218,0x1 -o $(TEST).$(OBJX) ++ -$(FC) $(FFLAGS) $(LDFLAGS) $(TEST).$(OBJX) $(LIBS) -o $(TEST).$(EXESUFFIX) ++ ++ ++run: ++ @echo ------------------------------------ executing test $(TEST) ++ $(TEST).$(EXESUFFIX) ++ ++verify: ; ++ +diff --git a/test/f90_correct/inc/inline_f90_str_copy_klen_2.mk b/test/f90_correct/inc/inline_f90_str_copy_klen_2.mk +new file mode 100644 +index 00000000..a2f1f193 +--- /dev/null ++++ b/test/f90_correct/inc/inline_f90_str_copy_klen_2.mk +@@ -0,0 +1,22 @@ ++# ++# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++# See https://llvm.org/LICENSE.txt for license information. ++# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++# ++ ++$(TEST): run ++ ++ ++build: $(SRC)/$(TEST).f90 ++ -$(RM) $(TEST).$(EXESUFFIX) core *.d *.mod FOR*.DAT FTN* ftn* fort.* ++ @echo ------------------------------------ building test $@ ++ -$(FC) -c $(FFLAGS) $(LDFLAGS) $(SRC)/$(TEST).f90 -Mx,218,0x1 -o $(TEST).$(OBJX) ++ -$(FC) $(FFLAGS) $(LDFLAGS) $(TEST).$(OBJX) $(LIBS) -o $(TEST).$(EXESUFFIX) ++ ++ ++run: ++ @echo ------------------------------------ executing test $(TEST) ++ $(TEST).$(EXESUFFIX) ++ ++verify: ; ++ +diff --git a/test/f90_correct/lit/inline_f90_str_copy_klen.sh b/test/f90_correct/lit/inline_f90_str_copy_klen.sh +new file mode 100644 +index 00000000..3880a96e +--- /dev/null ++++ b/test/f90_correct/lit/inline_f90_str_copy_klen.sh +@@ -0,0 +1,9 @@ ++# ++# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++# See https://llvm.org/LICENSE.txt for license information. ++# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++ ++# Shared lit script for each tests. Run bash commands that run tests with make. ++ ++# RUN: KEEP_FILES=%keep FLAGS=%flags TEST_SRC=%s MAKE_FILE_DIR=%S/.. bash %S/runmake | tee %t ++# RUN: cat %t | FileCheck %S/runmake +diff --git a/test/f90_correct/lit/inline_f90_str_copy_klen_2.sh b/test/f90_correct/lit/inline_f90_str_copy_klen_2.sh +new file mode 100644 +index 00000000..3880a96e +--- /dev/null ++++ b/test/f90_correct/lit/inline_f90_str_copy_klen_2.sh +@@ -0,0 +1,9 @@ ++# ++# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++# See https://llvm.org/LICENSE.txt for license information. ++# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++ ++# Shared lit script for each tests. Run bash commands that run tests with make. ++ ++# RUN: KEEP_FILES=%keep FLAGS=%flags TEST_SRC=%s MAKE_FILE_DIR=%S/.. bash %S/runmake | tee %t ++# RUN: cat %t | FileCheck %S/runmake +diff --git a/test/f90_correct/src/inline_f90_str_copy_klen.f90 b/test/f90_correct/src/inline_f90_str_copy_klen.f90 +new file mode 100644 +index 00000000..f2550a46 +--- /dev/null ++++ b/test/f90_correct/src/inline_f90_str_copy_klen.f90 +@@ -0,0 +1,73 @@ ++! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++! See https://llvm.org/LICENSE.txt for license information. ++! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++ ++! Program to test the inline of f90_strcmp_klen ++ ++program main ++ character(5) :: s1, s1_1, ans1 ++ character(3) :: s1_2 ++ character(8) :: s1_3 ++ character(9) :: s2, ans2 ++ character(11) :: s2_1, s2_2, s2_3 ++ character(9) :: s2_4 ++ character(6) :: s2_5 ++ character(3) :: s2_6, s2_7, s2_8 ++ character(2) :: s2_9 ++ ++ s1 = "aaaaa" ++ s1_1 = "bbbbb" ++ s1_2 = "ccc" ++ s1_3 = "ddddddd" ++ ++ s1 = s1_1 ++ print *, s1 ++ ++ s1 = s1_2 ++ print *, s1 ++ ++ s1 = s1_3 ++ print *, s1 ++ ++ s2 = "zzzzzzzzz" ++ s2_1 = "aaaaaaaaaaa" ++ s2_2 = "bbbbbbbbbbb" ++ s2_3 = "ccccccccccc" ++ s2_4 = "ddddddddd" ++ s2_5 = "eeeeee" ++ s2_6 = "fff" ++ s2_7 = "ggg" ++ s2_8 = "hh" ++ s2_9 = "i" ++ ++ s2 = s2_1 // s2_2 // s2_3 ++ print *, s2 ++ ++ s2 = s2_4 // s2_2 // s2_3 ++ print *, s2 ++ ++ s2 = s2_5 // s2_2 // s2_3 ++ print *, s2 ++ ++ s2 = s2_6 // s2_5 // s2_3 ++ print *, s2 ++ ++ s2 = s2_6 // s2_7 // s2_3 ++ print *, s2 ++ ++ s2 = s2_6 // s2_7 // s2_8 ++ print *, s2 ++ ++ s2 = s2_6 // s2_7 // s2_9 ++ print *, s2 ++ ++ print *, "PASS" ++ ++contains ++ function str_ne(s, t) result(res) ++ character(*) :: s, t ++ logical :: res ++ res = .false. ++ if (s /= t) res = .true. ++ end ++end +diff --git a/test/f90_correct/src/inline_f90_str_copy_klen_2.f90 b/test/f90_correct/src/inline_f90_str_copy_klen_2.f90 +new file mode 100644 +index 00000000..e0a19a35 +--- /dev/null ++++ b/test/f90_correct/src/inline_f90_str_copy_klen_2.f90 +@@ -0,0 +1,23 @@ ++! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. ++! See https://llvm.org/LICENSE.txt for license information. ++! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception ++ ++! Program to test the inline of f90_strcmp_klen when there is no constants ++! in procedure where the string compare exists. ++ ++program main ++ integer :: i ++ character(20) :: a, b, c, d ++ a = "aaaaaaaaaaaaaaa" ++ b = "aaaaaaaaaaaaaaa" ++ c = "aaaaaaaaaaaaaaa" ++ do i = 1, 100000000 ++ call test(a, b, c, d, 20) ++ enddo ++end ++subroutine test(a, b, c, d, n) ++ integer :: n ++ character(n) :: a, b, c, d ++ d = a // b // c ++end subroutine ++ +diff --git a/tools/flang2/flang2exe/inline_runtime.cpp b/tools/flang2/flang2exe/inline_runtime.cpp +index 429b84c4..14ff4a0e 100644 +--- a/tools/flang2/flang2exe/inline_runtime.cpp ++++ b/tools/flang2/flang2exe/inline_runtime.cpp +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + enum OT_CC_NAMES { + NONE = 0, +@@ -56,7 +57,10 @@ static void store_result_bb(SPTR, OPERAND *, OPERAND *, OPERAND *); + static void process_strlen_lt_zero(OPERAND *); + static INSTR_LIST *loop_s1_cmp_s2(OPERAND *, OPERAND *, OPERAND *, OPERAND *, + int); ++static INSTR_LIST *loop_copy_character(SPTR, OPERAND *, OPERAND *, OPERAND *, ++ OPERAND *, int ); + static INSTR_LIST *inline_f90_strcmp_klen(); ++static INSTR_LIST *inline_f90_str_copy_klen(); + static void init_inline_runtime_call(); + + static SPTR +@@ -758,6 +762,337 @@ inline_f90_strcmp_klen() + return runtime_instr; + } + ++static INSTR_LIST * ++loop_copy_character(SPTR input_str_select_next, OPERAND *input_len_opnd, ++ OPERAND *input_iter_opnd, OPERAND *target_len_opnd, ++ OPERAND *target_iter_opnd, int index){ ++ ++ INSTR_LIST *instr1, *input_index_instr, *target_index_instr; ++ INSTR_LIST *space_instr, *space_i8; ++ TMPS *input_len_tmps; ++ OPERAND *curr0_opnd, *curr1_opnd, *curr2_opnd; ++ OPERAND *target_str_opnd = runtime_instr->operands->next->next; ++ OPERAND *str_copy_str_op = runtime_instr->operands->next->next->next->next; ++ OPERAND *str_copy_len_op = str_copy_str_op->next; ++ ++ for (int i = 0; i < index; ++i){ ++ str_copy_str_op = str_copy_str_op->next->next; ++ str_copy_len_op = str_copy_len_op->next->next; ++ } ++ ++ LL_Type *i1_ty = make_int_lltype(1); ++ LL_Type *i8_ty = make_int_lltype(8); ++ LL_Type *i32_ty = make_int_lltype(32); ++ LL_Type *i64_ty = make_int_lltype(64); ++ LL_Type *ptr_i8_ty = make_ptr_lltype(i8_ty); ++ ++ // -------------------------------------------------------------------- ++ // %1 = bitcast [1 x i8]* "space_sym" to i8* ++ curr0_opnd = make_var_op(getstring(" ", 1)); ++ curr_instr = ++ gen_new_instr(curr_instr, I_BITCAST, ptr_i8_ty, curr0_opnd, NULL, NULL); ++ ++ // %2 = load volatile i8, i8* %1 ++ curr0_opnd = make_tmp_op(ptr_i8_ty, curr_instr->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i8_ty, curr0_opnd, NULL, NULL); ++ curr_instr->flags = LOOP_BACKEDGE_FLAG; ++ space_i8 = curr_instr; ++ ++ // %3 = zext i8 %2 to i32 ++ curr0_opnd = make_tmp_op(i8_ty, curr_instr->tmps); ++ curr_instr = ++ gen_new_instr(curr_instr, I_ZEXT, i32_ty, curr0_opnd, NULL, NULL); ++ space_instr = curr_instr; ++ ++ // store i64 %input_len_tmps, i64* input_len ++ input_len_tmps = str_copy_len_op->tmps; ++ if (input_len_tmps) ++ curr0_opnd = make_tmp_op(i64_ty, input_len_tmps); ++ else ++ curr0_opnd = mirror_nontmp_op(str_copy_len_op); ++ curr_instr = gen_new_st(curr_instr, curr0_opnd, input_len_opnd); ++ ++ process_strlen_lt_zero(input_len_opnd); ++ ++ // store i64 0, i64* %input_iter ++ curr0_opnd = make_constval_op(i64_ty, 0, 0); ++ curr_instr = gen_new_st(curr_instr, curr0_opnd, input_iter_opnd); ++ ++ // -------------------------------------------------------------------- ++ // Label for_loop_start ++ SPTR for_loop_start = mklabel("for_loop_start"); ++ curr0_opnd = make_label_op(for_loop_start); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ ++ // -------------------------------------------------------------------- ++ // %4 = load i64, i64* %target_len ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i64_ty, target_len_opnd, ++ NULL, NULL); ++ instr1 = curr_instr; ++ ++ // %5 = load i64, i64* %target_iter_opnd ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i64_ty, target_iter_opnd, ++ NULL, NULL); ++ target_index_instr = curr_instr; ++ ++ // %6 = icmp slt i64 %5, %4 ++ curr0_opnd = make_ot_cc_op(OT_SLT); ++ curr1_opnd = make_tmp_op(i64_ty, target_index_instr->tmps); ++ curr2_opnd = make_tmp_op(i64_ty, instr1->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_ICMP, i1_ty, curr0_opnd, curr1_opnd, ++ curr2_opnd); ++ ++ // br i1 %6, label %compare_input_index_len, label %input_str_select_next ++ SPTR compare_input_index_len = mklabel("compare_input_index_len"); ++ curr0_opnd = make_tmp_op(i1_ty, curr_instr->tmps); ++ curr1_opnd = make_target_op(compare_input_index_len); ++ curr2_opnd = make_target_op(input_str_select_next); ++ curr_instr = ++ gen_new_instr(curr_instr, I_BR, NULL, curr0_opnd, curr1_opnd, curr2_opnd); ++ ++ // -------------------------------------------------------------------- ++ // Label compare_input_index_len ++ curr0_opnd = make_label_op(compare_input_index_len); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ ++ // %7 = load i64, i64* %input_len ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i64_ty, input_len_opnd, NULL, ++ NULL); ++ instr1 = curr_instr; ++ ++ // %8 = load i64, i64* %input_iter ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i64_ty, input_iter_opnd, NULL, ++ NULL); ++ input_index_instr = curr_instr; ++ ++ // %9 = icmp slt i64 %8, %7 ++ curr0_opnd = make_ot_cc_op(OT_SLT); ++ curr1_opnd = make_tmp_op(i64_ty, input_index_instr->tmps); ++ curr2_opnd = make_tmp_op(i64_ty, instr1->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_ICMP, i1_ty, curr0_opnd, curr1_opnd, ++ curr2_opnd); ++ ++ // br i1 %6, label %input_str_copy, label %input_str_select_next ++ SPTR input_str_copy = mklabel("input_str_copy"); ++ curr0_opnd = make_tmp_op(i1_ty, curr_instr->tmps); ++ curr1_opnd = make_target_op(input_str_copy); ++ curr2_opnd = make_target_op(input_str_select_next); ++ curr_instr = gen_new_instr(curr_instr, I_BR, NULL, curr0_opnd, curr1_opnd, ++ curr2_opnd); ++ ++ // -------------------------------------------------------------------- ++ // Label input_str_copy ++ curr0_opnd = make_label_op(input_str_copy); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ ++ // %10 = getelementptr i8, i8* target_str, i64 %8 ++ curr0_opnd = make_tmp_op(ptr_i8_ty, target_str_opnd->tmps->info.idef->tmps); ++ curr1_opnd = make_tmp_op(i64_ty, target_index_instr->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_GEP, ptr_i8_ty, curr0_opnd, ++ curr1_opnd, NULL); ++ target_index_instr = curr_instr; ++ ++ // %11 = getelementptr i8, i8* str_copy_str, i64 %5 ++ curr0_opnd = make_tmp_op(ptr_i8_ty, str_copy_str_op->tmps->info.idef->tmps); ++ curr1_opnd = make_tmp_op(i64_ty, input_index_instr->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_GEP, ptr_i8_ty, curr0_opnd, ++ curr1_opnd, NULL); ++ ++ // %12 = load volatile i8, i8* %11 ++ curr0_opnd = make_tmp_op(ptr_i8_ty, curr_instr->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i8_ty, curr0_opnd, NULL, NULL); ++ // curr_instr->flags = LOOP_BACKEDGE_FLAG; ++ input_index_instr = curr_instr; ++ ++ // -------------------------------------------------------------------- ++ // store i8 %12, i8* target[%10] ++ curr0_opnd = make_tmp_op(i8_ty, input_index_instr->tmps); ++ curr1_opnd = make_tmp_op(ptr_i8_ty, target_index_instr->tmps); ++ curr_instr = gen_new_st(curr_instr, curr0_opnd, curr1_opnd); ++ ++ // br label %inc_iter_label ++ SPTR inc_iter_label = mklabel("inc_iter_label"); ++ curr0_opnd = make_target_op(inc_iter_label); ++ curr_instr = gen_new_instr(curr_instr, I_BR, NULL, curr0_opnd, NULL, NULL); ++ ++ // -------------------------------------------------------------------- ++ // Label inc_iter_label ++ curr0_opnd = make_label_op(inc_iter_label); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ ++ curr0_opnd = make_constval_op(i64_ty, 1, 0); ++ inc_loop_iter(target_iter_opnd, i64_ty, curr0_opnd); ++ inc_loop_iter(input_iter_opnd, i64_ty, curr0_opnd); ++ ++ // br label %for_loop_start ++ curr0_opnd = make_target_op(for_loop_start); ++ curr_instr = gen_new_instr(curr_instr, I_BR, NULL, curr0_opnd, NULL, NULL); ++ ++ return curr_instr; ++} ++ ++static INSTR_LIST * ++inline_f90_str_copy_klen(){ ++ dbg_line_op = runtime_instr->dbg_line_op; ++ OPERAND *input_str_opnd = runtime_instr->operands->next->next->next->next; ++ OPERAND *target_str_opnd = runtime_instr->operands->next->next; ++ OPERAND *target_len_opnd, *input_len_opnd; ++ OPERAND *target_iter_opnd, *input_iter_opnd; ++ OPERAND *curr0_opnd, *curr1_opnd, *curr2_opnd; ++ ++ INSTR_LIST *target_len, *input_len, *target_iter, *input_iter; ++ INSTR_LIST *target_str_index, *space_i8, *space_instr; ++ INSTR_LIST *head_instr; ++ INSTR_LIST *prev_instr = runtime_instr->prev; ++ ++ TMPS *target_len_tmps = runtime_instr->operands->next->next->next->tmps; ++ ++ std::vector str_copy_str_op, str_copy_len_op; ++ ++ LL_Type *i1_ty = make_int_lltype(1); ++ LL_Type *i8_ty = make_int_lltype(8); ++ LL_Type *i32_ty = make_int_lltype(32); ++ LL_Type *i64_ty = make_int_lltype(64); ++ LL_Type *ptr_i8_ty = make_ptr_lltype(i8_ty); ++ LL_Type *ptr_i64_ty = make_ptr_lltype(i64_ty); ++ ++ // Allocate space for target_len, input_len, target_iter, input_iter ++ target_len = gen_alloca_instr(ptr_i64_ty); ++ input_len = gen_alloca_instr(ptr_i64_ty); ++ target_iter = gen_alloca_instr(ptr_i64_ty); ++ input_iter = gen_alloca_instr(ptr_i64_ty); ++ ++ // Link allocas instructions ++ link_instrs(target_len, input_len); ++ link_instrs(input_len, target_iter); ++ link_instrs(target_iter, input_iter); ++ // Insert allocas ++ link_instrs(input_iter, top_instr->next); ++ link_instrs(top_instr, target_len); ++ ++ // Make tmp operands for allocas ++ target_len_opnd = make_tmp_op(ptr_i64_ty, target_len->tmps); ++ input_len_opnd = make_tmp_op(ptr_i64_ty, input_len->tmps); ++ target_iter_opnd = make_tmp_op(ptr_i64_ty, target_iter->tmps); ++ input_iter_opnd = make_tmp_op(ptr_i64_ty, input_iter->tmps); ++ ++ // store i64 %target_len_tmps, i64* %target_len ++ if (target_len_tmps) ++ curr0_opnd = make_tmp_op(i64_ty, target_len_tmps); ++ else ++ curr0_opnd = mirror_nontmp_op(runtime_instr->operands->next->next->next); ++ curr0_opnd->next = target_len_opnd; ++ curr_instr = gen_instr(I_STORE, NULL, NULL, curr0_opnd); ++ head_instr = curr_instr; ++ ++ process_strlen_lt_zero(target_len_opnd); ++ ++ // %0 = load i64, i64* %target_len ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i64_ty, target_len_opnd, NULL, NULL); ++ target_len = curr_instr; ++ ++ // store i64 0, i64* %target_iter ++ curr0_opnd = make_constval_op(i64_ty, 0, 0); ++ curr_instr = gen_new_st(curr_instr, curr0_opnd, target_iter_opnd); ++ ++ // %1 = bitcast [1 x i8]* "space_sym" to i8* ++ curr0_opnd = make_var_op(getstring(" ", 1)); ++ curr_instr = ++ gen_new_instr(curr_instr, I_BITCAST, ptr_i8_ty, curr0_opnd, NULL, NULL); ++ ++ // %2 = load volatile i8, i8* %1 ++ curr0_opnd = make_tmp_op(ptr_i8_ty, curr_instr->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i8_ty, curr0_opnd, NULL, NULL); ++ curr_instr->flags = LOOP_BACKEDGE_FLAG; ++ space_i8 = curr_instr; ++ ++ // %3 = zext i8 %2 to i32 ++ curr0_opnd = make_tmp_op(i8_ty, curr_instr->tmps); ++ curr_instr = ++ gen_new_instr(curr_instr, I_ZEXT, i32_ty, curr0_opnd, NULL, NULL); ++ space_instr = curr_instr; ++ ++ while (input_str_opnd){ ++ str_copy_str_op.push_back(input_str_opnd); ++ str_copy_len_op.push_back(input_str_opnd->next); ++ input_str_opnd = input_str_opnd->next->next; ++ } ++ ++ SPTR str_copy_input_end = mklabel("str_copy_input_end"); ++ SPTR str_copy_end = mklabel("str_copy_end"); ++ SPTR input_str_select_next; ++ SPTR input_str_select = mklabel("input_str_select"); ++ ++ for (unsigned int i = 0; i < str_copy_str_op.size(); ++i, input_str_select = input_str_select_next){ ++ if (i < str_copy_str_op.size() - 1){ ++ input_str_select_next = mklabel("input_str_select"); ++ } else { ++ input_str_select_next = str_copy_input_end; ++ } ++ ++ // Lable input_str_select ++ curr0_opnd = make_label_op(input_str_select); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ curr_instr = loop_copy_character(input_str_select_next, input_len_opnd, input_iter_opnd, ++ target_len_opnd, target_iter_opnd, i); ++ } ++ ++ // -------------------------------------------------------------------- ++ // label str_copy_input_end ++ curr0_opnd = make_label_op(str_copy_input_end); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ ++ // %4 = load i64, i64* %target_iter ++ curr_instr = gen_new_instr(curr_instr, I_LOAD, i64_ty, target_iter_opnd, NULL, NULL); ++ target_str_index = curr_instr; ++ ++ // %5 = icmp slt i64 %4, %0 ++ curr0_opnd = make_ot_cc_op(OT_SLT); ++ curr1_opnd = make_tmp_op(i64_ty, target_str_index->tmps); ++ curr2_opnd = make_tmp_op(i64_ty, target_len->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_ICMP, i1_ty, curr0_opnd, curr1_opnd, ++ curr2_opnd); ++ ++ // br i1 %5, label %write_space, label %str_copy_end ++ SPTR write_space = mklabel("write_space"); ++ curr0_opnd = make_tmp_op(i1_ty, curr_instr->tmps); ++ curr1_opnd = make_target_op(write_space); ++ curr2_opnd = make_target_op(str_copy_end); ++ curr_instr = gen_new_instr(curr_instr, I_BR, NULL, curr0_opnd, curr1_opnd, ++ curr2_opnd); ++ ++ // Label write_space ++ curr0_opnd = make_label_op(write_space); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ ++ // %6 = getelementptr i8, i8* target_str, i64 %4 ++ curr0_opnd = make_tmp_op(ptr_i8_ty, target_str_opnd->tmps->info.idef->tmps); ++ curr1_opnd = make_tmp_op(i64_ty, target_str_index->tmps); ++ curr_instr = gen_new_instr(curr_instr, I_GEP, ptr_i8_ty, curr0_opnd, ++ curr1_opnd, NULL); ++ ++ // store i8 %2, i8* target[%6] ++ curr0_opnd = make_tmp_op(i8_ty, space_i8->tmps); ++ curr1_opnd = make_tmp_op(ptr_i8_ty, curr_instr->tmps); ++ curr_instr = gen_new_st(curr_instr, curr0_opnd, curr1_opnd); ++ ++ curr0_opnd = make_constval_op(i64_ty, 1, 0); ++ inc_loop_iter(target_iter_opnd, i64_ty, curr0_opnd); ++ ++ // br label %str_copy_input_end ++ curr0_opnd = make_target_op(str_copy_input_end); ++ curr_instr = gen_new_instr(curr_instr, I_BR, NULL, curr0_opnd, NULL, NULL); ++ ++ // -------------------------------------------------------------------- ++ // Label %str_copy_end ++ curr0_opnd = make_label_op(str_copy_end); ++ curr_instr = gen_new_instr(curr_instr, I_NONE, NULL, curr0_opnd, NULL, NULL); ++ ++ link_instrs(prev_instr, head_instr); ++ link_instrs(curr_instr, runtime_instr->next); ++ return runtime_instr; ++} ++ + INSTR_LIST * + emit_inline_runtime_call(INSTR_LIST *top, INSTR_LIST *instr, + INLINE_RUNTIME_ID inline_runtime_id) +@@ -772,6 +1107,9 @@ emit_inline_runtime_call(INSTR_LIST *top, INSTR_LIST *instr, + case F90_STRCMP_KLEN: + prev_instr = inline_f90_strcmp_klen(); + break; ++ case F90_STR_COPY_KLEN: ++ prev_instr = inline_f90_str_copy_klen(); ++ break; + } + + return prev_instr; +@@ -782,6 +1120,8 @@ init_inline_runtime_call() + { + std::string f90_strcmp_klen = "@f90_strcmp_klen"; + inline_calls[f90_strcmp_klen] = F90_STRCMP_KLEN; ++ std::string f90_str_copy_klen = "@f90_str_copy_klen"; ++ inline_calls[f90_str_copy_klen] = F90_STR_COPY_KLEN; + } + + INLINE_RUNTIME_ID +diff --git a/tools/flang2/flang2exe/inline_runtime.h b/tools/flang2/flang2exe/inline_runtime.h +index 79ca0a66..29985ac6 100644 +--- a/tools/flang2/flang2exe/inline_runtime.h ++++ b/tools/flang2/flang2exe/inline_runtime.h +@@ -16,6 +16,7 @@ + enum INLINE_RUNTIME_ID { + NONE_ID = 0, + F90_STRCMP_KLEN, ++ F90_STR_COPY_KLEN, + }; + + INLINE_RUNTIME_ID get_inline_runtime_id(INSTR_LIST *instrs); diff --git a/flang.spec b/flang.spec index b8e35a60be33bc536121d79fc7dc4afbb32e7255..b95f15411111d59a965412906f0bbc840cb84526 100644 --- a/flang.spec +++ b/flang.spec @@ -2,7 +2,7 @@ Name: flang Version: flang_20210324 -Release: 5 +Release: 6 Summary: Fortran language compiler targeting LLVM License: Apache-2.0 @@ -12,6 +12,7 @@ Source0: flang-flang_20210324.tar.gz BuildRequires: gcc Requires: gcc >= 9.3.0 Patch0: 1-flang-runtime-inline.patch +Patch1: 2-inline_f90_str_copy_klen.patch %description Flang depends on a fork of the LLVM project (https://github.com/flang-compiler/classic-flang-llvm-project). The fork made some changes to the upstream LLVM project to support Flang toolchain. Flang cannot build independently for now. @@ -33,6 +34,9 @@ TODO: support build Flang. %changelog +* Thu Sep 8 2022 wangzhewei <51215902151@stu.ecnu.edu.cn> - flang_20210324-6 +- Add patch for inline of runtime function inline_f90_str_copy_klen + * Fri Aug 26 2022 wangzhewei <51215902151@stu.ecnu.edu.cn> - flang_20210324-5 - Fix patch 1 to apply on flang-flang_20210324.tar.gz