comparison gen/asm-x86-32.h @ 1102:ae950bd712d3

Use stringstream in asm generation instead of OutBuffer. Besides looking better, this should reduce allocations and copying.
author Frits van Bommel <fvbommel wxs.nl>
date Thu, 12 Mar 2009 14:08:57 +0100
parents 8bf8b058944a
children cdb7e1167803
comparison
equal deleted inserted replaced
1101:8bf8b058944a 1102:ae950bd712d3
1204 1204
1205 AsmStatement * stmt; 1205 AsmStatement * stmt;
1206 Scope * sc; 1206 Scope * sc;
1207 1207
1208 Token * token; 1208 Token * token;
1209 OutBuffer * insnTemplate; 1209 std::ostringstream insnTemplate;
1210 1210
1211 AsmOp op; 1211 AsmOp op;
1212 AsmOpInfo * opInfo; 1212 AsmOpInfo * opInfo;
1213 Operand operands[Max_Operands]; 1213 Operand operands[Max_Operands];
1214 Identifier * opIdent; 1214 Identifier * opIdent;
1217 AsmProcessor ( Scope * sc, AsmStatement * stmt ) 1217 AsmProcessor ( Scope * sc, AsmStatement * stmt )
1218 { 1218 {
1219 this->sc = sc; 1219 this->sc = sc;
1220 this->stmt = stmt; 1220 this->stmt = stmt;
1221 token = stmt->tokens; 1221 token = stmt->tokens;
1222 insnTemplate = new OutBuffer;
1223 1222
1224 opInfo = NULL; 1223 opInfo = NULL;
1225 1224
1226 if ( ! regInfo[0].ident ) 1225 if ( ! regInfo[0].ident )
1227 { 1226 {
1448 } 1447 }
1449 1448
1450 void setAsmCode() 1449 void setAsmCode()
1451 { 1450 {
1452 AsmCode * asmcode = new AsmCode ( N_Regs ); 1451 AsmCode * asmcode = new AsmCode ( N_Regs );
1453 asmcode->insnTemplateLen = insnTemplate->offset; 1452 asmcode->insnTemplate = insnTemplate.str();
1454 asmcode->insnTemplate = ( char* ) insnTemplate->extractData();
1455 stmt->asmcode = ( code* ) asmcode; 1453 stmt->asmcode = ( code* ) asmcode;
1456 } 1454 }
1457 1455
1458 // note: doesn't update AsmOp op 1456 // note: doesn't update AsmOp op
1459 bool matchOperands ( unsigned nOperands ) 1457 bool matchOperands ( unsigned nOperands )
1511 { 1509 {
1512 switch ( type ) 1510 switch ( type )
1513 { 1511 {
1514 case Arg_Integer: 1512 case Arg_Integer:
1515 if ( e->type->isunsigned() ) 1513 if ( e->type->isunsigned() )
1516 insnTemplate->printf ( "$%llu", e->toUInteger() ); 1514 insnTemplate << "$" << e->toUInteger();
1517 else 1515 else
1518 insnTemplate->printf ( "$%lld", e->toInteger() ); 1516 insnTemplate << "$" << e->toInteger();
1519 break; 1517 break;
1520 1518
1521 case Arg_Pointer: 1519 case Arg_Pointer:
1522 stmt->error ( "unsupported pointer reference to '%s' in naked asm", e->toChars() ); 1520 stmt->error ( "unsupported pointer reference to '%s' in naked asm", e->toChars() );
1523 break; 1521 break;
1534 break; 1532 break;
1535 } 1533 }
1536 1534
1537 // osx needs an extra underscore 1535 // osx needs an extra underscore
1538 if ( global.params.os == OSMacOSX ) 1536 if ( global.params.os == OSMacOSX )
1539 insnTemplate->writestring ( "_" ); 1537 insnTemplate << "_";
1540 1538
1541 // print out the mangle 1539 // print out the mangle
1542 insnTemplate->writestring ( vd->mangle() ); 1540 insnTemplate << vd->mangle();
1543 vd->nakedUse = true; 1541 vd->nakedUse = true;
1544 break; 1542 break;
1545 } 1543 }
1546 } 1544 }
1547 stmt->error ( "unsupported memory reference to '%s' in naked asm", e->toChars() ); 1545 stmt->error ( "unsupported memory reference to '%s' in naked asm", e->toChars() );
1552 break; 1550 break;
1553 } 1551 }
1554 } 1552 }
1555 else 1553 else
1556 { 1554 {
1557 insnTemplate->writestring ( ( char* ) fmt ); 1555 insnTemplate << fmt
1558 insnTemplate->printf ( "<<%s%d>>", ( mode==Mode_Input ) ?"in":"out", asmcode->args.size() ); 1556 << "<<" << (mode==Mode_Input ? "in" : "out") << asmcode->args.size() << ">>";
1559 asmcode->args.push_back ( AsmArg ( type, e, mode ) ); 1557 asmcode->args.push_back ( AsmArg ( type, e, mode ) );
1560 } 1558 }
1561 } 1559 }
1562 void addOperand2 ( const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input ) 1560 void addOperand2 ( const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input )
1563 { 1561 {
1564 assert ( !sc->func->naked ); 1562 assert ( !sc->func->naked );
1565 insnTemplate->writestring ( ( char* ) fmtpre ); 1563 insnTemplate << fmtpre
1566 insnTemplate->printf ( "<<%s%d>>", ( mode==Mode_Input ) ?"in":"out", asmcode->args.size() ); 1564 << "<<" << (mode==Mode_Input ? "in" : "out") << ">>"
1567 insnTemplate->writestring ( ( char* ) fmtpost ); 1565 << fmtpost;
1568 asmcode->args.push_back ( AsmArg ( type, e, mode ) ); 1566 asmcode->args.push_back ( AsmArg ( type, e, mode ) );
1569 } 1567 }
1570 1568
1571 void addLabel ( char* id ) 1569 void addLabel ( char* id )
1572 { 1570 {
1573 insnTemplate->writestring ( sc->func->mangle() ); 1571 insnTemplate << sc->func->mangle() << "_" << id;
1574 insnTemplate->writestring ( "_" );
1575 insnTemplate->writestring ( id );
1576 } 1572 }
1577 1573
1578 /* Determines whether the operand is a register, memory reference 1574 /* Determines whether the operand is a register, memory reference
1579 or immediate. Immediate addresses are currently classified as 1575 or immediate. Immediate addresses are currently classified as
1580 memory. This function is called before the exact instructions 1576 memory. This function is called before the exact instructions
1651 return Opr_Invalid; 1647 return Opr_Invalid;
1652 } 1648 }
1653 1649
1654 void writeReg ( Reg reg ) 1650 void writeReg ( Reg reg )
1655 { 1651 {
1656 insnTemplate->writestring ( ( char* ) "%" ); 1652 insnTemplate << "%" << regInfo[reg].gccName;
1657 insnTemplate->write ( regInfo[reg].gccName.c_str(), regInfo[reg].gccName.length() );
1658 } 1653 }
1659 1654
1660 bool opTakesLabel() 1655 bool opTakesLabel()
1661 { 1656 {
1662 switch ( op ) 1657 switch ( op )
1724 const char *mnemonic; 1719 const char *mnemonic;
1725 char type_char = 0; 1720 char type_char = 0;
1726 bool use_star; 1721 bool use_star;
1727 AsmArgMode mode; 1722 AsmArgMode mode;
1728 1723
1729 insnTemplate = new OutBuffer; 1724 insnTemplate.str("");
1730 // %% todo: special case for something.. 1725 // %% todo: special case for something..
1731 if ( opInfo->linkType == Out_Mnemonic ) 1726 if ( opInfo->linkType == Out_Mnemonic )
1732 mnemonic = alternateMnemonics[opInfo->link]; 1727 mnemonic = alternateMnemonics[opInfo->link];
1733 else 1728 else
1734 mnemonic = opIdent->string; 1729 mnemonic = opIdent->string;
1793 } 1788 }
1794 } 1789 }
1795 else if ( op == Op_Branch ) 1790 else if ( op == Op_Branch )
1796 { 1791 {
1797 if ( operands[0].dataSize == Far_Ptr ) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that.. 1792 if ( operands[0].dataSize == Far_Ptr ) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that..
1798 insnTemplate->writebyte ( 'l' ); 1793 insnTemplate << 'l';
1799 } 1794 }
1800 else if ( op == Op_fxch || op == Op_FfdRR_P || op == Op_FidR_P ) 1795 else if ( op == Op_fxch || op == Op_FfdRR_P || op == Op_FidR_P )
1801 { 1796 {
1802 if ( operands[0].cls == Opr_Mem && op == Op_FidR_P ) 1797 if ( operands[0].cls == Opr_Mem && op == Op_FidR_P )
1803 { 1798 {
1835 { 1830 {
1836 case Op_SizedStack: 1831 case Op_SizedStack:
1837 { 1832 {
1838 int mlen = strlen ( mnemonic ); 1833 int mlen = strlen ( mnemonic );
1839 if ( mnemonic[mlen-1] == 'd' ) 1834 if ( mnemonic[mlen-1] == 'd' )
1840 insnTemplate->write ( mnemonic, mlen-1 ); 1835 insnTemplate.write(mnemonic, mlen-1);
1841 else 1836 else
1842 { 1837 {
1843 insnTemplate->writestring ( ( char* ) mnemonic ); 1838 insnTemplate << mnemonic << 'w';
1844 insnTemplate->writebyte ( 'w' );
1845 } 1839 }
1846 } 1840 }
1847 break; 1841 break;
1848 case Op_cmpsd: 1842 case Op_cmpsd:
1849 case Op_insX: 1843 case Op_insX:
1854 case Op_stosX: 1848 case Op_stosX:
1855 { 1849 {
1856 int mlen = strlen ( mnemonic ); 1850 int mlen = strlen ( mnemonic );
1857 if ( mnemonic[mlen-1] == 'd' ) 1851 if ( mnemonic[mlen-1] == 'd' )
1858 { 1852 {
1859 insnTemplate->write ( mnemonic, mlen-1 ); 1853 insnTemplate.write(mnemonic, mlen-1) << 'l';
1860 insnTemplate->writebyte ( 'l' );
1861 } 1854 }
1862 else 1855 else
1863 { 1856 {
1864 insnTemplate->writestring ( ( char* ) mnemonic ); 1857 insnTemplate << mnemonic;
1865 } 1858 }
1866 } 1859 }
1867 break; 1860 break;
1868 case Op_movsx: 1861 case Op_movsx:
1869 case Op_movzx: 1862 case Op_movzx:
1886 default: 1879 default:
1887 stmt->error ( "invalid operand size/type" ); 1880 stmt->error ( "invalid operand size/type" );
1888 return false; 1881 return false;
1889 } 1882 }
1890 assert ( type_char != 0 ); 1883 assert ( type_char != 0 );
1891 insnTemplate->write ( mnemonic, mlen-1 ); 1884 insnTemplate.write(mnemonic, mlen-1) << tc_1 << type_char;
1892 insnTemplate->writebyte ( tc_1 );
1893 insnTemplate->writebyte ( type_char );
1894 } 1885 }
1895 break; 1886 break;
1896 default: 1887 default:
1897 insnTemplate->writestring ( ( char* ) mnemonic ); 1888 insnTemplate << mnemonic;
1898 if ( type_char ) 1889 if ( type_char )
1899 insnTemplate->writebyte ( type_char ); 1890 insnTemplate << type_char;
1900 break; 1891 break;
1901 } 1892 }
1902 1893
1903 switch ( opInfo->implicitClobbers & Clb_DXAX_Mask ) 1894 switch ( opInfo->implicitClobbers & Clb_DXAX_Mask )
1904 { 1895 {
1948 asmcode->regs[Reg_EBX] = true; 1939 asmcode->regs[Reg_EBX] = true;
1949 asmcode->regs[Reg_ECX] = true; 1940 asmcode->regs[Reg_ECX] = true;
1950 asmcode->regs[Reg_EDX] = true; 1941 asmcode->regs[Reg_EDX] = true;
1951 } 1942 }
1952 1943
1953 insnTemplate->writebyte ( ' ' ); 1944 insnTemplate << ' ';
1954 for ( int i__ = 0; i__ < nOperands; i__++ ) 1945 for ( int i__ = 0; i__ < nOperands; i__++ )
1955 { 1946 {
1956 int i; 1947 int i;
1957 if ( i__ != 0 ) 1948 if ( i__ != 0 )
1958 insnTemplate->writestring ( ( char* ) ", " ); 1949 insnTemplate << ", ";
1959 1950
1960 fmt = "$"; 1951 fmt = "$";
1961 1952
1962 switch ( op ) 1953 switch ( op )
1963 { 1954 {
2001 // handle __LOCAL_SIZE, which in this constant, is an immediate 1992 // handle __LOCAL_SIZE, which in this constant, is an immediate
2002 // should do this in slotexp.. 1993 // should do this in slotexp..
2003 addOperand ( "$", Arg_LocalSize, 1994 addOperand ( "$", Arg_LocalSize,
2004 ( Expression * ) operand->symbolDisplacement.data[0], asmcode ); 1995 ( Expression * ) operand->symbolDisplacement.data[0], asmcode );
2005 if ( operand->constDisplacement ) 1996 if ( operand->constDisplacement )
2006 insnTemplate->writebyte ( '+' ); 1997 insnTemplate << '+';
2007 else 1998 else
2008 break; 1999 break;
2009 } 2000 }
2010 2001
2011 if ( operand->symbolDisplacement.dim ) 2002 if ( operand->symbolDisplacement.dim )
2014 addOperand ( "$", Arg_Pointer, 2005 addOperand ( "$", Arg_Pointer,
2015 ( Expression * ) operand->symbolDisplacement.data[0], 2006 ( Expression * ) operand->symbolDisplacement.data[0],
2016 asmcode ); 2007 asmcode );
2017 2008
2018 if ( operand->constDisplacement ) 2009 if ( operand->constDisplacement )
2019 insnTemplate->writebyte ( '+' ); 2010 insnTemplate << '+';
2020 else 2011 else
2021 // skip the addOperand(fmt, Arg_Integer...) below 2012 // skip the addOperand(fmt, Arg_Integer...) below
2022 break; 2013 break;
2023 } 2014 }
2024 addOperand ( fmt, Arg_Integer, newIntExp ( operand->constDisplacement ), asmcode ); 2015 addOperand ( fmt, Arg_Integer, newIntExp ( operand->constDisplacement ), asmcode );
2031 { 2022 {
2032 asmcode->regs[clbr_reg] = true; 2023 asmcode->regs[clbr_reg] = true;
2033 } 2024 }
2034 } 2025 }
2035 if ( opTakesLabel() /*opInfo->takesLabel()*/ ) 2026 if ( opTakesLabel() /*opInfo->takesLabel()*/ )
2036 insnTemplate->writebyte ( '*' ); 2027 insnTemplate << '*';
2037 writeReg ( operand->reg ); 2028 writeReg ( operand->reg );
2038 /* 2029 /*
2039 insnTemplate->writestring("%"); 2030 insnTemplate << "%";
2040 insnTemplate->writestring(regInfo[operand->reg].name); 2031 insnTemplate << regInfo[operand->reg].name;
2041 */ 2032 */
2042 break; 2033 break;
2043 case Opr_Mem: 2034 case Opr_Mem:
2044 // better: use output operands for simple variable references 2035 // better: use output operands for simple variable references
2045 if ( ( opInfo->operands[i] & Opr_Update ) == Opr_Update ) 2036 if ( ( opInfo->operands[i] & Opr_Update ) == Opr_Update )
2059 2050
2060 if ( operand->segmentPrefix != Reg_Invalid || operand->constDisplacement ) 2051 if ( operand->segmentPrefix != Reg_Invalid || operand->constDisplacement )
2061 { 2052 {
2062 if ( operand->symbolDisplacement.dim ) 2053 if ( operand->symbolDisplacement.dim )
2063 { 2054 {
2064 insnTemplate->printf ( "%d", operand->constDisplacement ); 2055 insnTemplate << operand->constDisplacement << '+';
2065 insnTemplate->writebyte ( '+' );
2066 } 2056 }
2067 //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode); 2057 //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
2068 if ( opInfo->operands[i] & Opr_Dest ) 2058 if ( opInfo->operands[i] & Opr_Dest )
2069 asmcode->clobbersMemory = 1; 2059 asmcode->clobbersMemory = 1;
2070 } 2060 }
2071 2061
2072 if ( operand->segmentPrefix != Reg_Invalid ) 2062 if ( operand->segmentPrefix != Reg_Invalid )
2073 { 2063 {
2074 writeReg ( operand->segmentPrefix ); 2064 writeReg ( operand->segmentPrefix );
2075 insnTemplate->writebyte ( ':' ); 2065 insnTemplate << ':';
2076 } 2066 }
2077 if ( operand->symbolDisplacement.dim ) 2067 if ( operand->symbolDisplacement.dim )
2078 { 2068 {
2079 Expression * e = ( Expression * ) operand->symbolDisplacement.data[0]; 2069 Expression * e = ( Expression * ) operand->symbolDisplacement.data[0];
2080 Declaration * decl = 0; 2070 Declaration * decl = 0;
2161 { 2151 {
2162 use_star = false; 2152 use_star = false;
2163 // simply write out the mangle 2153 // simply write out the mangle
2164 // on osx, prepend extra _ 2154 // on osx, prepend extra _
2165 if ( global.params.os == OSMacOSX ) 2155 if ( global.params.os == OSMacOSX )
2166 insnTemplate->writestring ( "_" ); 2156 insnTemplate << "_";
2167 insnTemplate->writestring ( decl->mangle() ); 2157 insnTemplate << decl->mangle();
2168 // addOperand2("${", ":c}", Arg_Pointer, e, asmcode); 2158 // addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
2169 } 2159 }
2170 else 2160 else
2171 { 2161 {
2172 if ( use_star ) 2162 if ( use_star )
2173 { 2163 {
2174 insnTemplate->writebyte ( '*' ); 2164 insnTemplate << '*';
2175 use_star = false; 2165 use_star = false;
2176 } 2166 }
2177 2167
2178 if ( !sc->func->naked ) // no addrexp in naked asm please :) 2168 if ( !sc->func->naked ) // no addrexp in naked asm please :)
2179 { 2169 {
2185 addOperand ( fmt, Arg_Memory, e, asmcode, mode ); 2175 addOperand ( fmt, Arg_Memory, e, asmcode, mode );
2186 } 2176 }
2187 } 2177 }
2188 } 2178 }
2189 if ( use_star ) 2179 if ( use_star )
2190 insnTemplate->writebyte ( '*' ); 2180 insnTemplate << '*';
2191 if ( operand->segmentPrefix != Reg_Invalid && !(operand->constDisplacement) ) 2181 if ( operand->segmentPrefix != Reg_Invalid && !(operand->constDisplacement) )
2192 { 2182 {
2193 insnTemplate->printf ( "%d", operand->constDisplacement ); 2183 insnTemplate << operand->constDisplacement;
2194 if ( opInfo->operands[i] & Opr_Dest ) 2184 if ( opInfo->operands[i] & Opr_Dest )
2195 asmcode->clobbersMemory = 1; 2185 asmcode->clobbersMemory = 1;
2196 } 2186 }
2197 if ( operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid ) 2187 if ( operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid )
2198 { 2188 {
2199 insnTemplate->writebyte ( '(' ); 2189 insnTemplate << '(';
2200 if ( operand->baseReg != Reg_Invalid ) 2190 if ( operand->baseReg != Reg_Invalid )
2201 writeReg ( operand->baseReg ); 2191 writeReg ( operand->baseReg );
2202 if ( operand->indexReg != Reg_Invalid ) 2192 if ( operand->indexReg != Reg_Invalid )
2203 { 2193 {
2204 insnTemplate->writebyte ( ',' ); 2194 insnTemplate << ',';
2205 writeReg ( operand->indexReg ); 2195 writeReg ( operand->indexReg );
2206 if ( operand->scale ) 2196 if ( operand->scale )
2207 { 2197 {
2208 insnTemplate->printf ( ",%d", operand->scale ); 2198 insnTemplate << "," << operand->scale;
2209 } 2199 }
2210 } 2200 }
2211 insnTemplate->writebyte ( ')' ); 2201 insnTemplate << ')';
2212 if ( opInfo->operands[i] & Opr_Dest ) 2202 if ( opInfo->operands[i] & Opr_Dest )
2213 asmcode->clobbersMemory = 1; 2203 asmcode->clobbersMemory = 1;
2214 } 2204 }
2215 break; 2205 break;
2216 case Opr_Invalid: 2206 case Opr_Invalid:
2217 return false; 2207 return false;
2218 } 2208 }
2219 } 2209 }
2220 2210
2221 asmcode->insnTemplateLen = insnTemplate->offset; 2211 asmcode->insnTemplate = insnTemplate.str();
2222 asmcode->insnTemplate = ( char* ) insnTemplate->extractData();
2223 return true; 2212 return true;
2224 } 2213 }
2225 2214
2226 bool isIntExp ( Expression * exp ) 2215 bool isIntExp ( Expression * exp )
2227 { 2216 {
2889 if ( ( align & ( align - 1 ) ) == 0 ) 2878 if ( ( align & ( align - 1 ) ) == 0 )
2890 { 2879 {
2891 //FIXME: This printf is not portable. The use of `align` varies from system to system; 2880 //FIXME: This printf is not portable. The use of `align` varies from system to system;
2892 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary 2881 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary
2893 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 2882 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
2894 insnTemplate->printf ( ".balign\t%u", ( unsigned ) align ); 2883 insnTemplate << ".balign\t" << align;
2895 #else 2884 #else
2896 insnTemplate->printf ( ".align\t%u", ( unsigned ) align ); 2885 insnTemplate << ".align\t" << align;
2897 #endif 2886 #endif
2898 } 2887 }
2899 else 2888 else
2900 { 2889 {
2901 stmt->error ( "alignment must be a power of 2, not %u", ( unsigned ) align ); 2890 stmt->error ( "alignment must be a power of 2, not %u", ( unsigned ) align );
2906 2895
2907 void doEven() 2896 void doEven()
2908 { 2897 {
2909 // .align for GAS is in bits, others probably use bytes.. 2898 // .align for GAS is in bits, others probably use bytes..
2910 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 2899 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
2911 insnTemplate->writestring ( ( char * ) ".align\t2" ); 2900 insnTemplate << ".align\t2";
2912 #else 2901 #else
2913 insnTemplate->writestring ( ( char * ) ".align\t2" ); 2902 insnTemplate << ".align\t2";
2914 #endif 2903 #endif
2915 setAsmCode(); 2904 setAsmCode();
2916 } 2905 }
2917 2906
2918 void doNaked() 2907 void doNaked()