| @@ -559,14 +559,6 @@ static void apply_visibility(Sym *sym, CType *type) · 558 unmodified lines |
| 559 | | 559 | |
| 560 | /* ------------------------------------------------------------------------- */ | 560 | /* ------------------------------------------------------------------------- */ |
| 561 | | 561 | |
| 562 | ST_FUNC void swap(int *p, int *q) | | |
| 563 | { | | |
| 564 | int t; | | |
| 565 | t = *p; | | |
| 566 | *p = *q; | | |
| 567 | *q = t; | | |
| 568 | } | | |
| 569 | | | |
| 570 | static void vsetc(CType *type, int r, CValue *vc) | 562 | static void vsetc(CType *type, int r, CValue *vc) |
| 571 | { | 563 | { |
| 572 | int v; | 564 | int v; |
| @@ -583,12 +575,15 @@ static void vsetc(CType *type, int r, CValue *vc) · 10 unmodified lines |
| 583 | as their value might still be used for real. All values | 575 | as their value might still be used for real. All values |
| 584 | we push under nocode_wanted will eventually be popped | 576 | we push under nocode_wanted will eventually be popped |
| 585 | again, so that the VT_CMP/VT_JMP value will be in vtop | 577 | again, so that the VT_CMP/VT_JMP value will be in vtop |
| 586 | when code is unsuppressed again. */ | 578 | when code is unsuppressed again. |
| | 579 | |
| | 580 | Same logic below in vswap(); */ |
| 587 | if (vtop >= vstack && !nocode_wanted) { | 581 | if (vtop >= vstack && !nocode_wanted) { |
| 588 | v = vtop->r & VT_VALMASK; | 582 | v = vtop->r & VT_VALMASK; |
| 589 | if (v == VT_CMP || (v & ~1) == VT_JMP) | 583 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
| 590 | gv(RC_INT); | 584 | gv(RC_INT); |
| 591 | } | 585 | } |
| | 586 | |
| 592 | vtop++; | 587 | vtop++; |
| 593 | vtop->type = *type; | 588 | vtop->type = *type; |
| 594 | vtop->r = r; | 589 | vtop->r = r; |
| @@ -597,6 +592,38 @@ static void vsetc(CType *type, int r, CValue *vc) · 2 unmodified lines |
| 597 | vtop->sym = NULL; | 592 | vtop->sym = NULL; |
| 598 | } | 593 | } |
| 599 | | 594 | |
| | 595 | ST_FUNC void vswap(void) |
| | 596 | { |
| | 597 | SValue tmp; |
| | 598 | /* cannot vswap cpu flags. See comment at vsetc() above */ |
| | 599 | if (vtop >= vstack && !nocode_wanted) { |
| | 600 | int v = vtop->r & VT_VALMASK; |
| | 601 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
| | 602 | gv(RC_INT); |
| | 603 | } |
| | 604 | tmp = vtop[0]; |
| | 605 | vtop[0] = vtop[-1]; |
| | 606 | vtop[-1] = tmp; |
| | 607 | } |
| | 608 | |
| | 609 | /* pop stack value */ |
| | 610 | ST_FUNC void vpop(void) |
| | 611 | { |
| | 612 | int v; |
| | 613 | v = vtop->r & VT_VALMASK; |
| | 614 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
| | 615 | /* for x86, we need to pop the FP stack */ |
| | 616 | if (v == TREG_ST0) { |
| | 617 | o(0xd8dd); /* fstp %st(0) */ |
| | 618 | } else |
| | 619 | #endif |
| | 620 | if (v == VT_JMP || v == VT_JMPI) { |
| | 621 | /* need to put correct jump if && or || without test */ |
| | 622 | gsym(vtop->c.i); |
| | 623 | } |
| | 624 | vtop--; |
| | 625 | } |
| | 626 | |
| 600 | /* push constant of type "type" with useless value */ | 627 | /* push constant of type "type" with useless value */ |
| 601 | ST_FUNC void vpush(CType *type) | 628 | ST_FUNC void vpush(CType *type) |
| 602 | { | 629 | { |
| @@ -637,6 +664,71 @@ static inline void vpushll(long long v) · 34 unmodified lines |
| 637 | vpush64(VT_LLONG, v); | 664 | vpush64(VT_LLONG, v); |
| 638 | } | 665 | } |
| 639 | | 666 | |
| | 667 | ST_FUNC void vset(CType *type, int r, long v) |
| | 668 | { |
| | 669 | CValue cval; |
| | 670 | |
| | 671 | cval.i = v; |
| | 672 | vsetc(type, r, &cval); |
| | 673 | } |
| | 674 | |
| | 675 | static void vseti(int r, int v) |
| | 676 | { |
| | 677 | CType type; |
| | 678 | type.t = VT_INT; |
| | 679 | type.ref = 0; |
| | 680 | vset(&type, r, v); |
| | 681 | } |
| | 682 | |
| | 683 | ST_FUNC void vpushv(SValue *v) |
| | 684 | { |
| | 685 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
| | 686 | tcc_error("memory full (vstack)"); |
| | 687 | vtop++; |
| | 688 | *vtop = *v; |
| | 689 | } |
| | 690 | |
| | 691 | static void vdup(void) |
| | 692 | { |
| | 693 | vpushv(vtop); |
| | 694 | } |
| | 695 | |
| | 696 | /* rotate n first stack elements to the bottom |
| | 697 | I1 ... In -> I2 ... In I1 [top is right] |
| | 698 | */ |
| | 699 | ST_FUNC void vrotb(int n) |
| | 700 | { |
| | 701 | int i; |
| | 702 | SValue tmp; |
| | 703 | |
| | 704 | tmp = vtop[-n + 1]; |
| | 705 | for(i=-n+1;i!=0;i++) |
| | 706 | vtop[i] = vtop[i+1]; |
| | 707 | vtop[0] = tmp; |
| | 708 | } |
| | 709 | |
| | 710 | /* rotate the n elements before entry e towards the top |
| | 711 | I1 ... In ... -> In I1 ... I(n-1) ... [top is right] |
| | 712 | */ |
| | 713 | ST_FUNC void vrote(SValue *e, int n) |
| | 714 | { |
| | 715 | int i; |
| | 716 | SValue tmp; |
| | 717 | |
| | 718 | tmp = *e; |
| | 719 | for(i = 0;i < n - 1; i++) |
| | 720 | e[-i] = e[-i - 1]; |
| | 721 | e[-n + 1] = tmp; |
| | 722 | } |
| | 723 | |
| | 724 | /* rotate n first stack elements to the top |
| | 725 | I1 ... In -> In I1 ... I(n-1) [top is right] |
| | 726 | */ |
| | 727 | ST_FUNC void vrott(int n) |
| | 728 | { |
| | 729 | vrote(vtop, n); |
| | 730 | } |
| | 731 | |
| 640 | /* push a symbol value of TYPE */ | 732 | /* push a symbol value of TYPE */ |
| 641 | static inline void vpushsym(CType *type, Sym *sym) | 733 | static inline void vpushsym(CType *type, Sym *sym) |
| 642 | { | 734 | { |
| @@ -715,56 +807,6 @@ ST_FUNC void vpush_global_sym(CType *type, int v) · 72 unmodified lines |
| 715 | vpushsym(type, external_global_sym(v, type, 0)); | 807 | vpushsym(type, external_global_sym(v, type, 0)); |
| 716 | } | 808 | } |
| 717 | | 809 | |
| 718 | ST_FUNC void vset(CType *type, int r, long v) | | |
| 719 | { | | |
| 720 | CValue cval; | | |
| 721 | | | |
| 722 | cval.i = v; | | |
| 723 | vsetc(type, r, &cval); | | |
| 724 | } | | |
| 725 | | | |
| 726 | static void vseti(int r, int v) | | |
| 727 | { | | |
| 728 | CType type; | | |
| 729 | type.t = VT_INT; | | |
| 730 | type.ref = 0; | | |
| 731 | vset(&type, r, v); | | |
| 732 | } | | |
| 733 | | | |
| 734 | ST_FUNC void vswap(void) | | |
| 735 | { | | |
| 736 | SValue tmp; | | |
| 737 | /* cannot let cpu flags if other instruction are generated. Also | | |
| 738 | avoid leaving VT_JMP anywhere except on the top of the stack | | |
| 739 | because it would complicate the code generator. */ | | |
| 740 | if (vtop >= vstack) { | | |
| 741 | int v = vtop->r & VT_VALMASK; | | |
| 742 | if (v == VT_CMP || (v & ~1) == VT_JMP) | | |
| 743 | gv(RC_INT); | | |
| 744 | } | | |
| 745 | tmp = vtop[0]; | | |
| 746 | vtop[0] = vtop[-1]; | | |
| 747 | vtop[-1] = tmp; | | |
| 748 | | | |
| 749 | /* XXX: +2% overall speed possible with optimized memswap | | |
| 750 | * | | |
| 751 | * memswap(&vtop[0], &vtop[1], sizeof *vtop); | | |
| 752 | */ | | |
| 753 | } | | |
| 754 | | | |
| 755 | ST_FUNC void vpushv(SValue *v) | | |
| 756 | { | | |
| 757 | if (vtop >= vstack + (VSTACK_SIZE - 1)) | | |
| 758 | tcc_error("memory full (vstack)"); | | |
| 759 | vtop++; | | |
| 760 | *vtop = *v; | | |
| 761 | } | | |
| 762 | | | |
| 763 | static void vdup(void) | | |
| 764 | { | | |
| 765 | vpushv(vtop); | | |
| 766 | } | | |
| 767 | | | |
| 768 | /* save registers up to (vtop - n) stack entry */ | 810 | /* save registers up to (vtop - n) stack entry */ |
| 769 | ST_FUNC void save_regs(int n) | 811 | ST_FUNC void save_regs(int n) |
| 770 | { | 812 | { |
| @@ -1297,60 +1339,6 @@ static void lbuild(int t) · 526 unmodified lines |
| 1297 | } | 1339 | } |
| 1298 | #endif | 1340 | #endif |
| 1299 | | 1341 | |
| 1300 | /* rotate n first stack elements to the bottom | | |
| 1301 | I1 ... In -> I2 ... In I1 [top is right] | | |
| 1302 | */ | | |
| 1303 | ST_FUNC void vrotb(int n) | | |
| 1304 | { | | |
| 1305 | int i; | | |
| 1306 | SValue tmp; | | |
| 1307 | | | |
| 1308 | tmp = vtop[-n + 1]; | | |
| 1309 | for(i=-n+1;i!=0;i++) | | |
| 1310 | vtop[i] = vtop[i+1]; | | |
| 1311 | vtop[0] = tmp; | | |
| 1312 | } | | |
| 1313 | | | |
| 1314 | /* rotate the n elements before entry e towards the top | | |
| 1315 | I1 ... In ... -> In I1 ... I(n-1) ... [top is right] | | |
| 1316 | */ | | |
| 1317 | ST_FUNC void vrote(SValue *e, int n) | | |
| 1318 | { | | |
| 1319 | int i; | | |
| 1320 | SValue tmp; | | |
| 1321 | | | |
| 1322 | tmp = *e; | | |
| 1323 | for(i = 0;i < n - 1; i++) | | |
| 1324 | e[-i] = e[-i - 1]; | | |
| 1325 | e[-n + 1] = tmp; | | |
| 1326 | } | | |
| 1327 | | | |
| 1328 | /* rotate n first stack elements to the top | | |
| 1329 | I1 ... In -> In I1 ... I(n-1) [top is right] | | |
| 1330 | */ | | |
| 1331 | ST_FUNC void vrott(int n) | | |
| 1332 | { | | |
| 1333 | vrote(vtop, n); | | |
| 1334 | } | | |
| 1335 | | | |
| 1336 | /* pop stack value */ | | |
| 1337 | ST_FUNC void vpop(void) | | |
| 1338 | { | | |
| 1339 | int v; | | |
| 1340 | v = vtop->r & VT_VALMASK; | | |
| 1341 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) | | |
| 1342 | /* for x86, we need to pop the FP stack */ | | |
| 1343 | if (v == TREG_ST0) { | | |
| 1344 | o(0xd8dd); /* fstp %st(0) */ | | |
| 1345 | } else | | |
| 1346 | #endif | | |
| 1347 | if (v == VT_JMP || v == VT_JMPI) { | | |
| 1348 | /* need to put correct jump if && or || without test */ | | |
| 1349 | gsym(vtop->c.i); | | |
| 1350 | } | | |
| 1351 | vtop--; | | |
| 1352 | } | | |
| 1353 | | | |
| 1354 | /* convert stack entry to register and duplicate its value in another | 1342 | /* convert stack entry to register and duplicate its value in another |
| 1355 | register */ | 1343 | register */ |
| 1356 | static void gv_dup(void) | 1344 | static void gv_dup(void) |
| @@ -2025,7 +2013,7 @@ redo: · 668 unmodified lines |
| 2025 | /* Put pointer as first operand */ | 2013 | /* Put pointer as first operand */ |
| 2026 | if (bt2 == VT_PTR) { | 2014 | if (bt2 == VT_PTR) { |
| 2027 | vswap(); | 2015 | vswap(); |
| 2028 | swap(&t1, &t2); | 2016 | t = t1, t1 = t2, t2 = t; |
| 2029 | } | 2017 | } |
| 2030 | #if PTR_SIZE == 4 | 2018 | #if PTR_SIZE == 4 |
| 2031 | if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG) | 2019 | if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG) |
| @@ -4668,11 +4656,11 @@ ST_FUNC void unary(void) · 2636 unmodified lines |
| 4668 | subtract(-0, x). */ | 4656 | subtract(-0, x). */ |
| 4669 | vpush(&vtop->type); | 4657 | vpush(&vtop->type); |
| 4670 | if (t == VT_FLOAT) | 4658 | if (t == VT_FLOAT) |
| 4671 | vtop->c.f = -0.0f; | 4659 | vtop->c.f = -1.0 * 0.0; |
| 4672 | else if (t == VT_DOUBLE) | 4660 | else if (t == VT_DOUBLE) |
| 4673 | vtop->c.d = -0.0; | 4661 | vtop->c.d = -1.0 * 0.0; |
| 4674 | else | 4662 | else |
| 4675 | vtop->c.ld = -0.0; | 4663 | vtop->c.ld = -1.0 * 0.0; |
| 4676 | } else | 4664 | } else |
| 4677 | vpushi(0); | 4665 | vpushi(0); |
| 4678 | vswap(); | 4666 | vswap(); |
| @@ -5460,6 +5448,72 @@ static void label_or_decl(int l) · 781 unmodified lines |
| 5460 | decl(l); | 5448 | decl(l); |
| 5461 | } | 5449 | } |
| 5462 | | 5450 | |
| | 5451 | #ifndef TCC_TARGET_ARM64 |
| | 5452 | static void gfunc_return(CType *func_type) |
| | 5453 | { |
| | 5454 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) { |
| | 5455 | CType type, ret_type; |
| | 5456 | int ret_align, ret_nregs, regsize; |
| | 5457 | ret_nregs = gfunc_sret(func_type, func_var, &ret_type, |
| | 5458 | &ret_align, ®size); |
| | 5459 | if (0 == ret_nregs) { |
| | 5460 | /* if returning structure, must copy it to implicit |
| | 5461 | first pointer arg location */ |
| | 5462 | type = *func_type; |
| | 5463 | mk_pointer(&type); |
| | 5464 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
| | 5465 | indir(); |
| | 5466 | vswap(); |
| | 5467 | /* copy structure value to pointer */ |
| | 5468 | vstore(); |
| | 5469 | } else { |
| | 5470 | /* returning structure packed into registers */ |
| | 5471 | int r, size, addr, align; |
| | 5472 | size = type_size(func_type,&align); |
| | 5473 | if ((vtop->r != (VT_LOCAL | VT_LVAL) || |
| | 5474 | (vtop->c.i & (ret_align-1))) |
| | 5475 | && (align & (ret_align-1))) { |
| | 5476 | loc = (loc - size) & -ret_align; |
| | 5477 | addr = loc; |
| | 5478 | type = *func_type; |
| | 5479 | vset(&type, VT_LOCAL | VT_LVAL, addr); |
| | 5480 | vswap(); |
| | 5481 | vstore(); |
| | 5482 | vpop(); |
| | 5483 | vset(&ret_type, VT_LOCAL | VT_LVAL, addr); |
| | 5484 | } |
| | 5485 | vtop->type = ret_type; |
| | 5486 | if (is_float(ret_type.t)) |
| | 5487 | r = rc_fret(ret_type.t); |
| | 5488 | else |
| | 5489 | r = RC_IRET; |
| | 5490 | |
| | 5491 | if (ret_nregs == 1) |
| | 5492 | gv(r); |
| | 5493 | else { |
| | 5494 | for (;;) { |
| | 5495 | vdup(); |
| | 5496 | gv(r); |
| | 5497 | vpop(); |
| | 5498 | if (--ret_nregs == 0) |
| | 5499 | break; |
| | 5500 | /* We assume that when a structure is returned in multiple |
| | 5501 | registers, their classes are consecutive values of the |
| | 5502 | suite s(n) = 2^n */ |
| | 5503 | r <<= 1; |
| | 5504 | vtop->c.i += regsize; |
| | 5505 | } |
| | 5506 | } |
| | 5507 | } |
| | 5508 | } else if (is_float(func_type->t)) { |
| | 5509 | gv(rc_fret(func_type->t)); |
| | 5510 | } else { |
| | 5511 | gv(RC_IRET); |
| | 5512 | } |
| | 5513 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
| | 5514 | } |
| | 5515 | #endif |
| | 5516 | |
| 5463 | static int case_cmp(const void *pa, const void *pb) | 5517 | static int case_cmp(const void *pa, const void *pb) |
| 5464 | { | 5518 | { |
| 5465 | int64_t a = (*(struct case_t**) pa)->v1; | 5519 | int64_t a = (*(struct case_t**) pa)->v1; |
| @@ -5655,71 +5709,7 @@ static void block(int *bsym, int *csym, int is_expr) · 189 unmodified lines |
| 5655 | if (tok != ';') { | 5709 | if (tok != ';') { |
| 5656 | gexpr(); | 5710 | gexpr(); |
| 5657 | gen_assign_cast(&func_vt); | 5711 | gen_assign_cast(&func_vt); |
| 5658 | #ifdef TCC_TARGET_ARM64 | 5712 | gfunc_return(&func_vt); |
| 5659 | // Perhaps it would be better to use this for all backends: | | |
| 5660 | greturn(); | | |
| 5661 | #else | | |
| 5662 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { | | |
| 5663 | CType type, ret_type; | | |
| 5664 | int ret_align, ret_nregs, regsize; | | |
| 5665 | ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type, | | |
| 5666 | &ret_align, ®size); | | |
| 5667 | if (0 == ret_nregs) { | | |
| 5668 | /* if returning structure, must copy it to implicit | | |
| 5669 | first pointer arg location */ | | |
| 5670 | type = func_vt; | | |
| 5671 | mk_pointer(&type); | | |
| 5672 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); | | |
| 5673 | indir(); | | |
| 5674 | vswap(); | | |
| 5675 | /* copy structure value to pointer */ | | |
| 5676 | vstore(); | | |
| 5677 | } else { | | |
| 5678 | /* returning structure packed into registers */ | | |
| 5679 | int r, size, addr, align; | | |
| 5680 | size = type_size(&func_vt,&align); | | |
| 5681 | if ((vtop->r != (VT_LOCAL | VT_LVAL) || | | |
| 5682 | (vtop->c.i & (ret_align-1))) | | |
| 5683 | && (align & (ret_align-1))) { | | |
| 5684 | loc = (loc - size) & -ret_align; | | |
| 5685 | addr = loc; | | |
| 5686 | type = func_vt; | | |
| 5687 | vset(&type, VT_LOCAL | VT_LVAL, addr); | | |
| 5688 | vswap(); | | |
| 5689 | vstore(); | | |
| 5690 | vpop(); | | |
| 5691 | vset(&ret_type, VT_LOCAL | VT_LVAL, addr); | | |
| 5692 | } | | |
| 5693 | vtop->type = ret_type; | | |
| 5694 | if (is_float(ret_type.t)) | | |
| 5695 | r = rc_fret(ret_type.t); | | |
| 5696 | else | | |
| 5697 | r = RC_IRET; | | |
| 5698 | | | |
| 5699 | if (ret_nregs == 1) | | |
| 5700 | gv(r); | | |
| 5701 | else { | | |
| 5702 | for (;;) { | | |
| 5703 | vdup(); | | |
| 5704 | gv(r); | | |
| 5705 | vpop(); | | |
| 5706 | if (--ret_nregs == 0) | | |
| 5707 | break; | | |
| 5708 | /* We assume that when a structure is returned in multiple | | |
| 5709 | registers, their classes are consecutive values of the | | |
| 5710 | suite s(n) = 2^n */ | | |
| 5711 | r <<= 1; | | |
| 5712 | vtop->c.i += regsize; | | |
| 5713 | } | | |
| 5714 | } | | |
| 5715 | } | | |
| 5716 | } else if (is_float(func_vt.t)) { | | |
| 5717 | gv(rc_fret(func_vt.t)); | | |
| 5718 | } else { | | |
| 5719 | gv(RC_IRET); | | |
| 5720 | } | | |
| 5721 | #endif | | |
| 5722 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ | | |
| 5723 | } | 5713 | } |
| 5724 | skip(';'); | 5714 | skip(';'); |
| 5725 | /* jump unless last stmt in top-level block */ | 5715 | /* jump unless last stmt in top-level block */ |