| @@ -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 | 794 | /* Generate function call. The function address is pushed first, then |
| 741 | 795 | all the parameters in call order. This functions pops all the |
| 742 | 796 | parameters and the function address. */ |
| 743 | 797 | void gfunc_call(int nb_args) |
| 744 | 798 | { |
| 745 | | − int size, align, r, args_size, i; |
| 746 | | − Sym *func_sym; |
| 799 | + int size, align, r, args_size, i, ncrn, ncprn, argno, vfp_argno; |
| 747 | 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 | 819 | r = vtop->r & VT_VALMASK; |
| 751 | 820 | if (r == VT_CMP || (r & ~1) == VT_JMP) |
| 752 | 821 | gv(RC_INT); |
| @@ -763,39 +832,128 @@ void gfunc_call(int nb_args) · 10 unmodified lines |
| 763 | 832 | vpushi(0); |
| 764 | 833 | vtop->type.t = VT_LLONG; |
| 765 | 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 | 848 | for(i = nb_args + 1 ; i-- ;) { |
| 849 | + int j, assigned_vfpreg = 0; |
| 767 | 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 | 851 | switch(vtop[-i].type.t & VT_BTYPE) { |
| 782 | 852 | case VT_STRUCT: |
| 783 | 853 | case VT_FLOAT: |
| 784 | 854 | case VT_DOUBLE: |
| 785 | 855 | case VT_LDOUBLE: |
| 786 | | − size = type_size(&vtop[-i].type, &align); |
| 787 | | − size = (size + 3) & -4; |
| 788 | | − args_size += size; |
| 856 | +#ifdef TCC_ARM_HARDFLOAT |
| 857 | + if (!variadic) { |
| 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 | 919 | break; |
| 920 | + } |
| 921 | + continue; |
| 790 | 922 | default: |
| 791 | | − plan[nb_args-1-i][0]=args_size/4; |
| 792 | | − args_size += 4; |
| 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; |
| 923 | + if (!i) { |
| 924 | + break; |
| 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 | 957 | args_size = keep = 0; |
| 800 | 958 | for(i = 0;i < nb_args; i++) { |
| 801 | 959 | vrotb(keep+1); |
| @@ -814,6 +972,12 @@ void gfunc_call(int nb_args) · 12 unmodified lines |
| 814 | 972 | vtop--; |
| 815 | 973 | args_size += size; |
| 816 | 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 | 981 | #ifdef TCC_ARM_VFP |
| 818 | 982 | r=vfpr(gv(RC_FLOAT))<<12; |
| 819 | 983 | size=4; |
| @@ -848,57 +1012,59 @@ void gfunc_call(int nb_args) · 28 unmodified lines |
| 848 | 1012 | size=4; |
| 849 | 1013 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
| 850 | 1014 | lexpand_nr(); |
| 851 | | − s=RC_INT; |
| 852 | | − if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) { |
| 853 | | − s=regmask(plan[nb_args-i-1][1]); |
| 854 | | − todo&=~(1<<plan[nb_args-i-1][1]); |
| 855 | | − } |
| 856 | | − if(s==RC_INT) { |
| 857 | | − r = gv(s); |
| 1015 | + s=-1; |
| 1016 | + if(--argno<4 && plan[argno][1]!=-1) |
| 1017 | + s=plan[argno][1]; |
| 1018 | + argno++; |
| 1019 | + size = 8; |
| 1020 | + if(s==-1) { |
| 1021 | + r = gv(RC_INT); |
| 858 | 1022 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
| 859 | 1023 | vtop--; |
| 860 | 1024 | } else { |
| 1025 | + size=0; |
| 861 | 1026 | plan2[keep]=s; |
| 862 | 1027 | keep++; |
| 863 | 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 | 1034 | #ifdef TCC_ARM_EABI |
| 873 | 1035 | if(vtop->type.t == VT_VOID) { |
| 874 | | − if(s == RC_INT) |
| 1036 | + if(s == -1) |
| 875 | 1037 | o(0xE24DD004); /* sub sp,sp,#4 */ |
| 876 | 1038 | vtop--; |
| 877 | 1039 | } else |
| 878 | | −#endif |
| 879 | | − if(s == RC_INT) { |
| 880 | | − r = gv(s); |
| 1040 | +#endif |
| 1041 | + if(s == -1) { |
| 1042 | + r = gv(RC_INT); |
| 881 | 1043 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
| 882 | 1044 | vtop--; |
| 883 | 1045 | } else { |
| 1046 | + size=0; |
| 884 | 1047 | plan2[keep]=s; |
| 885 | 1048 | keep++; |
| 886 | 1049 | } |
| 887 | 1050 | args_size += size; |
| 888 | 1051 | } |
| 889 | 1052 | } |
| 890 | | − for(i=keep;i--;) { |
| 891 | | − gv(plan2[i]); |
| 892 | | − vrott(keep); |
| 1053 | + for(i = 0; i < keep; i++) { |
| 1054 | + vrotb(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 | 1061 | save_regs(keep); /* save used temporary registers */ |
| 895 | 1062 | keep++; |
| 896 | | − if(args_size) { |
| 897 | | − int n; |
| 898 | | − n=args_size/4; |
| 899 | | − if(n>4) |
| 900 | | − n=4; |
| 901 | | − todo&=((1<<n)-1); |
| 1063 | + if(ncrn) { |
| 1064 | + int nb_regs=0; |
| 1065 | + if (ncrn>4) |
| 1066 | + ncrn=4; |
| 1067 | + todo&=((1<<ncrn)-1); |
| 902 | 1068 | if(todo) { |
| 903 | 1069 | int i; |
| 904 | 1070 | o(0xE8BD0000|todo); |
| @@ -907,12 +1073,31 @@ save_regs(keep); /* save used temporary registers */ · 2 unmodified lines |
| 907 | 1073 | vpushi(0); |
| 908 | 1074 | vtop->r=i; |
| 909 | 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 | 1100 | vrotb(keep); |
| 915 | | − func_sym = vtop->type.ref; |
| 916 | 1101 | gcall_or_jmp(0); |
| 917 | 1102 | if (args_size) |
| 918 | 1103 | gadd_sp(args_size); |
| @@ -924,7 +1109,11 @@ save_regs(keep); /* save used temporary registers */ · 5 unmodified lines |
| 924 | 1109 | ++keep; |
| 925 | 1110 | } |
| 926 | 1111 | #ifdef TCC_ARM_VFP |
| 1112 | +#ifdef TCC_ARM_HARDFLOAT |
| 1113 | + else if(variadic && is_float(vtop->type.ref->type.t)) { |
| 1114 | +#else |
| 927 | 1115 | else if(is_float(vtop->type.ref->type.t)) { |
| 1116 | +#endif |
| 928 | 1117 | if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { |
| 929 | 1118 | o(0xEE000A10); /* fmsr s0,r0 */ |
| 930 | 1119 | } else { |
| @@ -942,26 +1131,38 @@ save_regs(keep); /* save used temporary registers */ · 11 unmodified lines |
| 942 | 1131 | void gfunc_prolog(CType *func_type) |
| 943 | 1132 | { |
| 944 | 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 | 1139 | sym = func_type->ref; |
| 948 | 1140 | func_vt = sym->type; |
| 949 | | − |
| 950 | | − n = 0; |
| 951 | | − addr = 0; |
| 1141 | + |
| 1142 | + n = nf = 0; |
| 1143 | + variadic = (func_type->ref->c == FUNC_ELLIPSIS); |
| 952 | 1144 | if((func_vt.t & VT_BTYPE) == VT_STRUCT |
| 953 | 1145 | && type_size(&func_vt,&align) > 4) |
| 954 | 1146 | { |
| 955 | | − func_vc = addr; |
| 956 | | − addr += 4; |
| 957 | 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 | 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 | 1164 | o(0xE1A0C00D); /* mov ip,sp */ |
| 964 | | − if(func_type->ref->c == FUNC_ELLIPSIS) |
| 1165 | + if(variadic) |
| 965 | 1166 | n=4; |
| 966 | 1167 | if(n) { |
| 967 | 1168 | if(n>4) |
| @@ -971,20 +1172,57 @@ void gfunc_prolog(CType *func_type) · 3 unmodified lines |
| 971 | 1172 | #endif |
| 972 | 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 | 1181 | o(0xE92D5800); /* save fp, ip, lr */ |
| 975 | 1182 | o(0xE28DB00C); /* add fp, sp, #12 */ |
| 976 | 1183 | func_sub_sp_offset = ind; |
| 977 | | − o(0xE1A00000); /* nop, leave space for stack adjustment */ |
| 978 | | − while ((sym = sym->next)) { |
| 979 | | − CType *type; |
| 980 | | − type = &sym->type; |
| 981 | | − size = type_size(type, &align); |
| 982 | | − size = (size + 3) & -4; |
| 1184 | + o(0xE1A00000); /* nop, leave space for stack adjustment in epilogue */ |
| 1185 | + { |
| 1186 | + int addr, pn = struct_ret, sn = 0; /* pn=core, sn=stack */ |
| 1187 | + |
| 1188 | +#ifdef TCC_ARM_HARDFLOAT |
| 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 | 1218 | #ifdef TCC_ARM_EABI |
| 984 | | − addr = (addr + align - 1) & -align; |
| 1219 | + sn = (sn + (align-1)/4) & -(align/4); |
| 985 | 1220 | #endif |
| 986 | | − sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr); |
| 987 | | − addr += size; |
| 1221 | + addr = (n + nf + sn) * 4; |
| 1222 | + sn += size; |
| 1223 | + } |
| 1224 | + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr); |
| 1225 | + } |
| 988 | 1226 | } |
| 989 | 1227 | last_itod_magic=0; |
| 990 | 1228 | leaffunc = 1; |
| @@ -997,6 +1235,8 @@ void gfunc_epilog(void) · 6 unmodified lines |
| 997 | 1235 | uint32_t x; |
| 998 | 1236 | int diff; |
| 999 | 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 | 1240 | if(is_float(func_vt.t)) { |
| 1001 | 1241 | if((func_vt.t & VT_BTYPE) == VT_FLOAT) |
| 1002 | 1242 | o(0xEE100A10); /* fmrs r0, s0 */ |