| @@ -737,16 +737,85 @@ static void gcall_or_jmp(int is_jmp) · 736 unmodified lines |
| 737 | } | 737 | } |
| 738 | } | 738 | } |
| 739 | | 739 | |
| | 740 | #ifdef TCC_ARM_HARDFLOAT |
| | 741 | static int is_float_hgen_aggr(CType *type) |
| | 742 | { |
| | 743 | if ((type->t & VT_BTYPE) == VT_STRUCT) { |
| | 744 | struct Sym *ref; |
| | 745 | int btype, nb_fields = 0; |
| | 746 | |
| | 747 | ref = type->ref; |
| | 748 | btype = ref->type.t & VT_BTYPE; |
| | 749 | if (btype == VT_FLOAT || btype == VT_DOUBLE) { |
| | 750 | for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++); |
| | 751 | return !ref && nb_fields <= 4; |
| | 752 | } |
| | 753 | } |
| | 754 | return 0; |
| | 755 | } |
| | 756 | |
| | 757 | struct avail_regs { |
| | 758 | /* worst case: f(float, double, 3 float struct, double, 3 float struct, double) */ |
| | 759 | signed char avail[3]; |
| | 760 | int first_hole; |
| | 761 | int last_hole; |
| | 762 | int first_free_reg; |
| | 763 | }; |
| | 764 | |
| | 765 | #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 } |
| | 766 | |
| | 767 | /* Assign a register for a CPRC param with correct size and alignment |
| | 768 | * size and align are in bytes, as returned by type_size */ |
| | 769 | int assign_fpreg(struct avail_regs *avregs, int align, int size) |
| | 770 | { |
| | 771 | int first_reg = 0; |
| | 772 | |
| | 773 | if (avregs->first_free_reg == -1) |
| | 774 | return -1; |
| | 775 | if (align >> 3) { // alignment needed (base type: double) |
| | 776 | first_reg = avregs->first_free_reg; |
| | 777 | if (first_reg & 1) |
| | 778 | avregs->avail[avregs->last_hole++] = first_reg++; |
| | 779 | } else { |
| | 780 | if (size == 4 && avregs->first_hole != avregs->last_hole) |
| | 781 | return avregs->avail[avregs->first_hole++]; |
| | 782 | else |
| | 783 | first_reg = avregs->first_free_reg; |
| | 784 | } |
| | 785 | if (first_reg + size / 4 <= 16) { |
| | 786 | avregs->first_free_reg = first_reg + size / 4; |
| | 787 | return first_reg; |
| | 788 | } |
| | 789 | avregs->first_free_reg = -1; |
| | 790 | return -1; |
| | 791 | } |
| | 792 | #endif |
| | 793 | |
| 740 | /* Generate function call. The function address is pushed first, then | 794 | /* Generate function call. The function address is pushed first, then |
| 741 | all the parameters in call order. This functions pops all the | 795 | all the parameters in call order. This functions pops all the |
| 742 | parameters and the function address. */ | 796 | parameters and the function address. */ |
| 743 | void gfunc_call(int nb_args) | 797 | void gfunc_call(int nb_args) |
| 744 | { | 798 | { |
| 745 | int size, align, r, args_size, i; | 799 | int size, align, r, args_size, i, ncrn, ncprn, argno, vfp_argno; |
| 746 | Sym *func_sym; | | |
| 747 | signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; | 800 | signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; |
| 748 | int todo=0xf, keep, plan2[4]={0,0,0,0}; | 801 | SValue *before_stack = NULL; /* SValue before first on stack argument */ |
| | 802 | SValue *before_vfpreg_hfa = NULL; /* SValue before first in VFP reg hfa argument */ |
| | 803 | #ifdef TCC_ARM_HARDFLOAT |
| | 804 | struct avail_regs avregs = AVAIL_REGS_INITIALIZER; |
| | 805 | signed char vfp_plan[16]; |
| | 806 | int plan2[4+16]; |
| | 807 | int variadic; |
| | 808 | #else |
| | 809 | int plan2[4]={0,0,0,0}; |
| | 810 | #endif |
| | 811 | int vfp_todo=0; |
| | 812 | int todo=0, keep; |
| 749 | | 813 | |
| | 814 | #ifdef TCC_ARM_HARDFLOAT |
| | 815 | memset(vfp_plan, -1, sizeof(vfp_plan)); |
| | 816 | memset(plan2, 0, sizeof(plan2)); |
| | 817 | variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS); |
| | 818 | #endif |
| 750 | r = vtop->r & VT_VALMASK; | 819 | r = vtop->r & VT_VALMASK; |
| 751 | if (r == VT_CMP || (r & ~1) == VT_JMP) | 820 | if (r == VT_CMP || (r & ~1) == VT_JMP) |
| 752 | gv(RC_INT); | 821 | gv(RC_INT); |
| @@ -763,39 +832,128 @@ void gfunc_call(int nb_args) · 10 unmodified lines |
| 763 | vpushi(0); | 832 | vpushi(0); |
| 764 | vtop->type.t = VT_LLONG; | 833 | vtop->type.t = VT_LLONG; |
| 765 | args_size = 0; | 834 | args_size = 0; |
| | 835 | #endif |
| | 836 | ncrn = ncprn = argno = vfp_argno = 0; |
| | 837 | /* Assign argument to registers and stack with alignment. |
| | 838 | If, considering alignment constraints, enough registers of the correct type |
| | 839 | (core or VFP) are free for the current argument, assign them to it, else |
| | 840 | allocate on stack with correct alignment. Whenever a structure is allocated |
| | 841 | in registers or on stack, it is always put on the stack at this stage. The |
| | 842 | stack is divided in 3 zones. The zone are, from low addresses to high |
| | 843 | addresses: structures to be loaded in core registers, structures to be |
| | 844 | loaded in VFP registers, argument allocated to stack. SValue's representing |
| | 845 | structures in the first zone are moved just after the SValue pointed by |
| | 846 | before_vfpreg_hfa. SValue's representing structures in the second zone are |
| | 847 | moved just after the SValue pointer by before_stack. */ |
| 766 | for(i = nb_args + 1 ; i-- ;) { | 848 | for(i = nb_args + 1 ; i-- ;) { |
| | 849 | int j, assigned_vfpreg = 0; |
| 767 | size = type_size(&vtop[-i].type, &align); | 850 | size = type_size(&vtop[-i].type, &align); |
| 768 | if(args_size & (align-1)) { | | |
| 769 | vpushi(0); | | |
| 770 | vtop->type.t = VT_VOID; /* padding */ | | |
| 771 | vrott(i+2); | | |
| 772 | args_size += 4; | | |
| 773 | ++nb_args; | | |
| 774 | } | | |
| 775 | args_size += (size + 3) & -4; | | |
| 776 | } | | |
| 777 | vtop--; | | |
| 778 | #endif | | |
| 779 | args_size = 0; | | |
| 780 | for(i = nb_args ; i-- && args_size < 16 ;) { | | |
| 781 | switch(vtop[-i].type.t & VT_BTYPE) { | 851 | switch(vtop[-i].type.t & VT_BTYPE) { |
| 782 | case VT_STRUCT: | 852 | case VT_STRUCT: |
| 783 | case VT_FLOAT: | 853 | case VT_FLOAT: |
| 784 | case VT_DOUBLE: | 854 | case VT_DOUBLE: |
| 785 | case VT_LDOUBLE: | 855 | case VT_LDOUBLE: |
| 786 | size = type_size(&vtop[-i].type, &align); | 856 | #ifdef TCC_ARM_HARDFLOAT |
| 787 | size = (size + 3) & -4; | 857 | if (!variadic) { |
| 788 | args_size += size; | 858 | int hfa = 0; /* Homogeneous float aggregate */ |
| | 859 | |
| | 860 | if (is_float(vtop[-i].type.t) |
| | 861 | || (hfa = is_float_hgen_aggr(&vtop[-i].type))) { |
| | 862 | int end_reg; |
| | 863 | |
| | 864 | assigned_vfpreg = assign_fpreg(&avregs, align, size); |
| | 865 | end_reg = assigned_vfpreg + (size - 1) / 4; |
| | 866 | if (assigned_vfpreg >= 0) { |
| | 867 | vfp_plan[vfp_argno++]=TREG_F0 + assigned_vfpreg/2; |
| | 868 | if (hfa) { |
| | 869 | /* before_stack can only have been set because all core registers |
| | 870 | are assigned, so no need to care about before_vfpreg_hfa if |
| | 871 | before_stack is set */ |
| | 872 | if (before_stack) { |
| | 873 | vrote(&vtop[-i], &vtop[-i] - before_stack); |
| | 874 | before_stack++; |
| | 875 | } else if (!before_vfpreg_hfa) |
| | 876 | before_vfpreg_hfa = &vtop[-i-1]; |
| | 877 | for (j = assigned_vfpreg; j <= end_reg; j++) |
| | 878 | vfp_todo|=(1<<j); |
| | 879 | } |
| | 880 | continue; |
| | 881 | } else { |
| | 882 | if (!hfa) |
| | 883 | vfp_argno++; |
| | 884 | /* No need to update before_stack as no more hfa can be allocated in |
| | 885 | VFP regs */ |
| | 886 | if (!before_vfpreg_hfa) |
| | 887 | before_vfpreg_hfa = &vtop[-i-1]; |
| | 888 | break; |
| | 889 | } |
| | 890 | } |
| | 891 | } |
| | 892 | #endif |
| | 893 | ncrn = (ncrn + (align-1)/4) & -(align/4); |
| | 894 | size = (size + 3) & -4; |
| | 895 | if (ncrn + size/4 <= 4 || (ncrn < 4 && assigned_vfpreg != -1)) { |
| | 896 | /* Either there is HFA in VFP registers, or there is arguments on stack, |
| | 897 | it cannot be both. Hence either before_stack already points after |
| | 898 | the slot where the vtop[-i] SValue is moved, or before_stack will not |
| | 899 | be used */ |
| | 900 | if (before_vfpreg_hfa) { |
| | 901 | vrote(&vtop[-i], &vtop[-i] - before_vfpreg_hfa); |
| | 902 | before_vfpreg_hfa++; |
| | 903 | } |
| | 904 | for (j = ncrn; j < 4 && j < ncrn + size / 4; j++) |
| | 905 | todo|=(1<<j); |
| | 906 | ncrn+=size/4; |
| | 907 | if (ncrn > 4) { |
| | 908 | args_size = (ncrn - 4) * 4; |
| | 909 | if (!before_stack) |
| | 910 | before_stack = &vtop[-i-1]; |
| | 911 | } |
| | 912 | } |
| | 913 | else { |
| | 914 | ncrn = 4; |
| | 915 | /* No need to set before_vfpreg_hfa if not set since there will no |
| | 916 | longer be any structure assigned to core registers */ |
| | 917 | if (!before_stack) |
| | 918 | before_stack = &vtop[-i-1]; |
| 789 | break; | 919 | break; |
| | 920 | } |
| | 921 | continue; |
| 790 | default: | 922 | default: |
| 791 | plan[nb_args-1-i][0]=args_size/4; | 923 | if (!i) { |
| 792 | args_size += 4; | 924 | break; |
| 793 | if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) { | | |
| 794 | plan[nb_args-1-i][1]=args_size/4; | | |
| 795 | args_size += 4; | | |
| 796 | } | 925 | } |
| | 926 | if (ncrn < 4) { |
| | 927 | int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG; |
| | 928 | |
| | 929 | if (is_long) { |
| | 930 | ncrn = (ncrn + 1) & -2; |
| | 931 | if (ncrn == 4) { |
| | 932 | argno++; |
| | 933 | break; |
| | 934 | } |
| | 935 | } |
| | 936 | plan[argno++][0]=ncrn++; |
| | 937 | if (is_long) { |
| | 938 | plan[argno-1][1]=ncrn++; |
| | 939 | } |
| | 940 | continue; |
| | 941 | } |
| | 942 | argno++; |
| 797 | } | 943 | } |
| | 944 | #ifdef TCC_ARM_EABI |
| | 945 | if(args_size & (align-1)) { |
| | 946 | vpushi(0); |
| | 947 | vtop->type.t = VT_VOID; /* padding */ |
| | 948 | vrott(i+2); |
| | 949 | args_size += 4; |
| | 950 | nb_args++; |
| | 951 | argno++; |
| | 952 | } |
| | 953 | #endif |
| | 954 | args_size += (size + 3) & -4; |
| 798 | } | 955 | } |
| | 956 | vtop--; |
| 799 | args_size = keep = 0; | 957 | args_size = keep = 0; |
| 800 | for(i = 0;i < nb_args; i++) { | 958 | for(i = 0;i < nb_args; i++) { |
| 801 | vrotb(keep+1); | 959 | vrotb(keep+1); |
| @@ -814,6 +972,12 @@ void gfunc_call(int nb_args) · 12 unmodified lines |
| 814 | vtop--; | 972 | vtop--; |
| 815 | args_size += size; | 973 | args_size += size; |
| 816 | } else if (is_float(vtop->type.t)) { | 974 | } else if (is_float(vtop->type.t)) { |
| | 975 | #ifdef TCC_ARM_HARDFLOAT |
| | 976 | if (!variadic && --vfp_argno<16 && vfp_plan[vfp_argno]!=-1) { |
| | 977 | plan2[keep++]=vfp_plan[vfp_argno]; |
| | 978 | continue; |
| | 979 | } |
| | 980 | #endif |
| 817 | #ifdef TCC_ARM_VFP | 981 | #ifdef TCC_ARM_VFP |
| 818 | r=vfpr(gv(RC_FLOAT))<<12; | 982 | r=vfpr(gv(RC_FLOAT))<<12; |
| 819 | size=4; | 983 | size=4; |
| @@ -848,57 +1012,59 @@ void gfunc_call(int nb_args) · 28 unmodified lines |
| 848 | size=4; | 1012 | size=4; |
| 849 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { | 1013 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
| 850 | lexpand_nr(); | 1014 | lexpand_nr(); |
| 851 | s=RC_INT; | 1015 | s=-1; |
| 852 | if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) { | 1016 | if(--argno<4 && plan[argno][1]!=-1) |
| 853 | s=regmask(plan[nb_args-i-1][1]); | 1017 | s=plan[argno][1]; |
| 854 | todo&=~(1<<plan[nb_args-i-1][1]); | 1018 | argno++; |
| 855 | } | 1019 | size = 8; |
| 856 | if(s==RC_INT) { | 1020 | if(s==-1) { |
| 857 | r = gv(s); | 1021 | r = gv(RC_INT); |
| 858 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ | 1022 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
| 859 | vtop--; | 1023 | vtop--; |
| 860 | } else { | 1024 | } else { |
| | 1025 | size=0; |
| 861 | plan2[keep]=s; | 1026 | plan2[keep]=s; |
| 862 | keep++; | 1027 | keep++; |
| 863 | vswap(); | 1028 | vswap(); |
| 864 | } | 1029 | } |
| 865 | size = 8; | | |
| 866 | } | | |
| 867 | s=RC_INT; | | |
| 868 | if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) { | | |
| 869 | s=regmask(plan[nb_args-i-1][0]); | | |
| 870 | todo&=~(1<<plan[nb_args-i-1][0]); | | |
| 871 | } | 1030 | } |
| | 1031 | s=-1; |
| | 1032 | if(--argno<4 && plan[argno][0]!=-1) |
| | 1033 | s=plan[argno][0]; |
| 872 | #ifdef TCC_ARM_EABI | 1034 | #ifdef TCC_ARM_EABI |
| 873 | if(vtop->type.t == VT_VOID) { | 1035 | if(vtop->type.t == VT_VOID) { |
| 874 | if(s == RC_INT) | 1036 | if(s == -1) |
| 875 | o(0xE24DD004); /* sub sp,sp,#4 */ | 1037 | o(0xE24DD004); /* sub sp,sp,#4 */ |
| 876 | vtop--; | 1038 | vtop--; |
| 877 | } else | 1039 | } else |
| 878 | #endif | 1040 | #endif |
| 879 | if(s == RC_INT) { | 1041 | if(s == -1) { |
| 880 | r = gv(s); | 1042 | r = gv(RC_INT); |
| 881 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ | 1043 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
| 882 | vtop--; | 1044 | vtop--; |
| 883 | } else { | 1045 | } else { |
| | 1046 | size=0; |
| 884 | plan2[keep]=s; | 1047 | plan2[keep]=s; |
| 885 | keep++; | 1048 | keep++; |
| 886 | } | 1049 | } |
| 887 | args_size += size; | 1050 | args_size += size; |
| 888 | } | 1051 | } |
| 889 | } | 1052 | } |
| 890 | for(i=keep;i--;) { | 1053 | for(i = 0; i < keep; i++) { |
| 891 | gv(plan2[i]); | 1054 | vrotb(keep); |
| 892 | vrott(keep); | 1055 | gv(regmask(plan2[i])); |
| | 1056 | /* arg is in s(2d+1): plan2[i]<plan2[i+1] => alignment occured (ex f,d,f) */ |
| | 1057 | if (i < keep - 1 && is_float(vtop->type.t) && (plan2[i] <= plan2[i + 1])) { |
| | 1058 | o(0xEEF00A40|(vfpr(plan2[i])<<12)|vfpr(plan2[i])); |
| | 1059 | } |
| 893 | } | 1060 | } |
| 894 | save_regs(keep); /* save used temporary registers */ | 1061 | save_regs(keep); /* save used temporary registers */ |
| 895 | keep++; | 1062 | keep++; |
| 896 | if(args_size) { | 1063 | if(ncrn) { |
| 897 | int n; | 1064 | int nb_regs=0; |
| 898 | n=args_size/4; | 1065 | if (ncrn>4) |
| 899 | if(n>4) | 1066 | ncrn=4; |
| 900 | n=4; | 1067 | todo&=((1<<ncrn)-1); |
| 901 | todo&=((1<<n)-1); | | |
| 902 | if(todo) { | 1068 | if(todo) { |
| 903 | int i; | 1069 | int i; |
| 904 | o(0xE8BD0000|todo); | 1070 | o(0xE8BD0000|todo); |
| @@ -907,12 +1073,31 @@ save_regs(keep); /* save used temporary registers */ · 2 unmodified lines |
| 907 | vpushi(0); | 1073 | vpushi(0); |
| 908 | vtop->r=i; | 1074 | vtop->r=i; |
| 909 | keep++; | 1075 | keep++; |
| | 1076 | nb_regs++; |
| 910 | } | 1077 | } |
| 911 | } | 1078 | } |
| 912 | args_size-=n*4; | 1079 | args_size-=nb_regs*4; |
| | 1080 | } |
| | 1081 | if(vfp_todo) { |
| | 1082 | int nb_fregs=0; |
| | 1083 | |
| | 1084 | for(i=0;i<16;i++) |
| | 1085 | if(vfp_todo&(1<<i)) { |
| | 1086 | o(0xED9D0A00|(i&1)<<22|(i>>1)<<12|nb_fregs); |
| | 1087 | vpushi(0); |
| | 1088 | /* There might be 2 floats in a double VFP reg but that doesn't seem |
| | 1089 | to matter */ |
| | 1090 | if (!(i%2)) |
| | 1091 | vtop->r=TREG_F0+i/2; |
| | 1092 | keep++; |
| | 1093 | nb_fregs++; |
| | 1094 | } |
| | 1095 | if (nb_fregs) { |
| | 1096 | gadd_sp(nb_fregs*4); |
| | 1097 | args_size-=nb_fregs*4; |
| | 1098 | } |
| 913 | } | 1099 | } |
| 914 | vrotb(keep); | 1100 | vrotb(keep); |
| 915 | func_sym = vtop->type.ref; | | |
| 916 | gcall_or_jmp(0); | 1101 | gcall_or_jmp(0); |
| 917 | if (args_size) | 1102 | if (args_size) |
| 918 | gadd_sp(args_size); | 1103 | gadd_sp(args_size); |
| @@ -924,7 +1109,11 @@ save_regs(keep); /* save used temporary registers */ · 5 unmodified lines |
| 924 | ++keep; | 1109 | ++keep; |
| 925 | } | 1110 | } |
| 926 | #ifdef TCC_ARM_VFP | 1111 | #ifdef TCC_ARM_VFP |
| | 1112 | #ifdef TCC_ARM_HARDFLOAT |
| | 1113 | else if(variadic && is_float(vtop->type.ref->type.t)) { |
| | 1114 | #else |
| 927 | else if(is_float(vtop->type.ref->type.t)) { | 1115 | else if(is_float(vtop->type.ref->type.t)) { |
| | 1116 | #endif |
| 928 | if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { | 1117 | if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { |
| 929 | o(0xEE000A10); /* fmsr s0,r0 */ | 1118 | o(0xEE000A10); /* fmsr s0,r0 */ |
| 930 | } else { | 1119 | } else { |
| @@ -942,26 +1131,38 @@ save_regs(keep); /* save used temporary registers */ · 11 unmodified lines |
| 942 | void gfunc_prolog(CType *func_type) | 1131 | void gfunc_prolog(CType *func_type) |
| 943 | { | 1132 | { |
| 944 | Sym *sym,*sym2; | 1133 | Sym *sym,*sym2; |
| 945 | int n,addr,size,align; | 1134 | int n,nf,size,align, variadic, struct_ret = 0; |
| | 1135 | #ifdef TCC_ARM_HARDFLOAT |
| | 1136 | struct avail_regs avregs = AVAIL_REGS_INITIALIZER; |
| | 1137 | #endif |
| 946 | | 1138 | |
| 947 | sym = func_type->ref; | 1139 | sym = func_type->ref; |
| 948 | func_vt = sym->type; | 1140 | func_vt = sym->type; |
| 949 | | 1141 | |
| 950 | n = 0; | 1142 | n = nf = 0; |
| 951 | addr = 0; | 1143 | variadic = (func_type->ref->c == FUNC_ELLIPSIS); |
| 952 | if((func_vt.t & VT_BTYPE) == VT_STRUCT | 1144 | if((func_vt.t & VT_BTYPE) == VT_STRUCT |
| 953 | && type_size(&func_vt,&align) > 4) | 1145 | && type_size(&func_vt,&align) > 4) |
| 954 | { | 1146 | { |
| 955 | func_vc = addr; | | |
| 956 | addr += 4; | | |
| 957 | n++; | 1147 | n++; |
| | 1148 | struct_ret = 1; |
| 958 | } | 1149 | } |
| 959 | for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) { | 1150 | for(sym2=sym->next;sym2 && (n<4 || nf<16);sym2=sym2->next) { |
| 960 | size = type_size(&sym2->type, &align); | 1151 | size = type_size(&sym2->type, &align); |
| 961 | n += (size + 3) / 4; | 1152 | #ifdef TCC_ARM_HARDFLOAT |
| | 1153 | if (!variadic && (is_float(sym2->type.t) |
| | 1154 | || is_float_hgen_aggr(&sym2->type))) { |
| | 1155 | int tmpnf = assign_fpreg(&avregs, align, size) + 1; |
| | 1156 | nf = (tmpnf > nf) ? tmpnf : nf; |
| | 1157 | } else |
| | 1158 | #endif |
| | 1159 | if (n < 4) |
| | 1160 | n += (size + 3) / 4; |
| 962 | } | 1161 | } |
| | 1162 | if (struct_ret) |
| | 1163 | func_vc = nf * 4; |
| 963 | o(0xE1A0C00D); /* mov ip,sp */ | 1164 | o(0xE1A0C00D); /* mov ip,sp */ |
| 964 | if(func_type->ref->c == FUNC_ELLIPSIS) | 1165 | if(variadic) |
| 965 | n=4; | 1166 | n=4; |
| 966 | if(n) { | 1167 | if(n) { |
| 967 | if(n>4) | 1168 | if(n>4) |
| @@ -971,20 +1172,57 @@ void gfunc_prolog(CType *func_type) · 3 unmodified lines |
| 971 | #endif | 1172 | #endif |
| 972 | o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */ | 1173 | o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */ |
| 973 | } | 1174 | } |
| | 1175 | if (nf) { |
| | 1176 | if (nf>16) |
| | 1177 | nf=16; |
| | 1178 | nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */ |
| | 1179 | o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */ |
| | 1180 | } |
| 974 | o(0xE92D5800); /* save fp, ip, lr */ | 1181 | o(0xE92D5800); /* save fp, ip, lr */ |
| 975 | o(0xE28DB00C); /* add fp, sp, #12 */ | 1182 | o(0xE28DB00C); /* add fp, sp, #12 */ |
| 976 | func_sub_sp_offset = ind; | 1183 | func_sub_sp_offset = ind; |
| 977 | o(0xE1A00000); /* nop, leave space for stack adjustment */ | 1184 | o(0xE1A00000); /* nop, leave space for stack adjustment in epilogue */ |
| 978 | while ((sym = sym->next)) { | 1185 | { |
| 979 | CType *type; | 1186 | int addr, pn = struct_ret, sn = 0; /* pn=core, sn=stack */ |
| 980 | type = &sym->type; | 1187 | |
| 981 | size = type_size(type, &align); | 1188 | #ifdef TCC_ARM_HARDFLOAT |
| 982 | size = (size + 3) & -4; | 1189 | avregs = AVAIL_REGS_INITIALIZER; |
| | 1190 | #endif |
| | 1191 | while ((sym = sym->next)) { |
| | 1192 | CType *type; |
| | 1193 | type = &sym->type; |
| | 1194 | size = type_size(type, &align); |
| | 1195 | size = (size + 3) >> 2; |
| | 1196 | #ifdef TCC_ARM_HARDFLOAT |
| | 1197 | if (!variadic && (is_float(sym->type.t) |
| | 1198 | || is_float_hgen_aggr(&sym->type))) { |
| | 1199 | int fpn = assign_fpreg(&avregs, align, size << 2); |
| | 1200 | if (fpn >= 0) { |
| | 1201 | addr = fpn * 4; |
| | 1202 | } else |
| | 1203 | goto from_stack; |
| | 1204 | } else |
| | 1205 | #endif |
| | 1206 | if (pn < 4) { |
| | 1207 | #ifdef TCC_ARM_EABI |
| | 1208 | pn = (pn + (align-1)/4) & -(align/4); |
| | 1209 | #endif |
| | 1210 | addr = (nf + pn) * 4; |
| | 1211 | pn += size; |
| | 1212 | if (!sn && pn > 4) |
| | 1213 | sn = (pn - 4); |
| | 1214 | } else { |
| | 1215 | #ifdef TCC_ARM_HARDFLOAT |
| | 1216 | from_stack: |
| | 1217 | #endif |
| 983 | #ifdef TCC_ARM_EABI | 1218 | #ifdef TCC_ARM_EABI |
| 984 | addr = (addr + align - 1) & -align; | 1219 | sn = (sn + (align-1)/4) & -(align/4); |
| 985 | #endif | 1220 | #endif |
| 986 | sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr); | 1221 | addr = (n + nf + sn) * 4; |
| 987 | addr += size; | 1222 | sn += size; |
| | 1223 | } |
| | 1224 | sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr); |
| | 1225 | } |
| 988 | } | 1226 | } |
| 989 | last_itod_magic=0; | 1227 | last_itod_magic=0; |
| 990 | leaffunc = 1; | 1228 | leaffunc = 1; |
| @@ -997,6 +1235,8 @@ void gfunc_epilog(void) · 6 unmodified lines |
| 997 | uint32_t x; | 1235 | uint32_t x; |
| 998 | int diff; | 1236 | int diff; |
| 999 | #ifdef TCC_ARM_EABI | 1237 | #ifdef TCC_ARM_EABI |
| | 1238 | /* Useless but harmless copy of the float result into main register(s) in case |
| | 1239 | of variadic function in the hardfloat variant */ |
| 1000 | if(is_float(func_vt.t)) { | 1240 | if(is_float(func_vt.t)) { |
| 1001 | if((func_vt.t & VT_BTYPE) == VT_FLOAT) | 1241 | if((func_vt.t & VT_BTYPE) == VT_FLOAT) |
| 1002 | o(0xEE100A10); /* fmrs r0, s0 */ | 1242 | o(0xEE100A10); /* fmrs r0, s0 */ |