comparison gen/asm-x86-64.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 d03814546977
comparison
equal deleted inserted replaced
1101:8bf8b058944a 1102:ae950bd712d3
1326 1326
1327 AsmStatement * stmt; 1327 AsmStatement * stmt;
1328 Scope * sc; 1328 Scope * sc;
1329 1329
1330 Token * token; 1330 Token * token;
1331 OutBuffer * insnTemplate; 1331 std::ostringstream insnTemplate;
1332 1332
1333 AsmOp op; 1333 AsmOp op;
1334 AsmOpInfo * opInfo; 1334 AsmOpInfo * opInfo;
1335 Operand operands[Max_Operands]; 1335 Operand operands[Max_Operands];
1336 Identifier * opIdent; 1336 Identifier * opIdent;
1339 AsmProcessor ( Scope * sc, AsmStatement * stmt ) 1339 AsmProcessor ( Scope * sc, AsmStatement * stmt )
1340 { 1340 {
1341 this->sc = sc; 1341 this->sc = sc;
1342 this->stmt = stmt; 1342 this->stmt = stmt;
1343 token = stmt->tokens; 1343 token = stmt->tokens;
1344 insnTemplate = new OutBuffer;
1345 1344
1346 opInfo = NULL; 1345 opInfo = NULL;
1347 1346
1348 if ( ! regInfo[0].ident ) 1347 if ( ! regInfo[0].ident )
1349 { 1348 {
1570 } 1569 }
1571 1570
1572 void setAsmCode() 1571 void setAsmCode()
1573 { 1572 {
1574 AsmCode * asmcode = new AsmCode ( N_Regs ); 1573 AsmCode * asmcode = new AsmCode ( N_Regs );
1575 asmcode->insnTemplateLen = insnTemplate->offset; 1574 asmcode->insnTemplate = insnTemplate.str();
1576 asmcode->insnTemplate = ( char* ) insnTemplate->extractData();
1577 stmt->asmcode = ( code* ) asmcode; 1575 stmt->asmcode = ( code* ) asmcode;
1578 } 1576 }
1579 1577
1580 // note: doesn't update AsmOp op 1578 // note: doesn't update AsmOp op
1581 bool matchOperands ( unsigned nOperands ) 1579 bool matchOperands ( unsigned nOperands )
1633 { 1631 {
1634 switch ( type ) 1632 switch ( type )
1635 { 1633 {
1636 case Arg_Integer: 1634 case Arg_Integer:
1637 if ( e->type->isunsigned() ) 1635 if ( e->type->isunsigned() )
1638 insnTemplate->printf ( "$%llu", e->toUInteger() ); 1636 insnTemplate << "$" << e->toUInteger();
1639 else 1637 else
1640 insnTemplate->printf ( "$%lld", e->toInteger() ); 1638 insnTemplate << "$" << e->toInteger();
1641 break; 1639 break;
1642 1640
1643 case Arg_Pointer: 1641 case Arg_Pointer:
1644 stmt->error ( "unsupported pointer reference to '%s' in naked asm", e->toChars() ); 1642 stmt->error ( "unsupported pointer reference to '%s' in naked asm", e->toChars() );
1645 break; 1643 break;
1656 break; 1654 break;
1657 } 1655 }
1658 1656
1659 // osx needs an extra underscore 1657 // osx needs an extra underscore
1660 if ( global.params.os == OSMacOSX ) 1658 if ( global.params.os == OSMacOSX )
1661 insnTemplate->writestring ( "_" ); 1659 insnTemplate << "_";
1662 1660
1663 // print out the mangle 1661 // print out the mangle
1664 insnTemplate->writestring ( vd->mangle() ); 1662 insnTemplate << vd->mangle();
1665 vd->nakedUse = true; 1663 vd->nakedUse = true;
1666 break; 1664 break;
1667 } 1665 }
1668 } 1666 }
1669 stmt->error ( "unsupported memory reference to '%s' in naked asm", e->toChars() ); 1667 stmt->error ( "unsupported memory reference to '%s' in naked asm", e->toChars() );
1674 break; 1672 break;
1675 } 1673 }
1676 } 1674 }
1677 else 1675 else
1678 { 1676 {
1679 insnTemplate->writestring ( ( char* ) fmt ); 1677 insnTemplate << fmt
1680 insnTemplate->printf ( "<<%s%d>>", ( mode==Mode_Input ) ?"in":"out", asmcode->args.size() ); 1678 << "<<" << (mode==Mode_Input ? "in" : "out") << asmcode->args.size() << ">>";
1681 asmcode->args.push_back ( AsmArg ( type, e, mode ) ); 1679 asmcode->args.push_back ( AsmArg ( type, e, mode ) );
1682 } 1680 }
1683 } 1681 }
1684 void addOperand2 ( const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input ) 1682 void addOperand2 ( const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input )
1685 { 1683 {
1686 assert ( !sc->func->naked ); 1684 assert ( !sc->func->naked );
1687 insnTemplate->writestring ( ( char* ) fmtpre ); 1685 insnTemplate << fmtpre
1688 insnTemplate->printf ( "<<%s%d>>", ( mode==Mode_Input ) ?"in":"out", asmcode->args.size() ); 1686 << "<<" << (mode==Mode_Input ? "in" : "out") << ">>"
1689 insnTemplate->writestring ( ( char* ) fmtpost ); 1687 << fmtpost;
1690 asmcode->args.push_back ( AsmArg ( type, e, mode ) ); 1688 asmcode->args.push_back ( AsmArg ( type, e, mode ) );
1691 } 1689 }
1692 1690
1693 void addLabel ( char* id ) 1691 void addLabel ( char* id )
1694 { 1692 {
1695 insnTemplate->writestring ( sc->func->mangle() ); 1693 insnTemplate << sc->func->mangle() << "_" << id;
1696 insnTemplate->writestring ( "_" );
1697 insnTemplate->writestring ( id );
1698 } 1694 }
1699 1695
1700 /* Determines whether the operand is a register, memory reference 1696 /* Determines whether the operand is a register, memory reference
1701 or immediate. Immediate addresses are currently classified as 1697 or immediate. Immediate addresses are currently classified as
1702 memory. This function is called before the exact instructions 1698 memory. This function is called before the exact instructions
1776 return Opr_Invalid; 1772 return Opr_Invalid;
1777 } 1773 }
1778 1774
1779 void writeReg ( Reg reg ) 1775 void writeReg ( Reg reg )
1780 { 1776 {
1781 insnTemplate->writestring ( ( char* ) "%" ); 1777 insnTemplate << "%" << regInfo[reg].gccName;
1782 insnTemplate->write ( regInfo[reg].gccName.c_str(), regInfo[reg].gccName.length() );
1783 } 1778 }
1784 1779
1785 bool opTakesLabel() 1780 bool opTakesLabel()
1786 { 1781 {
1787 switch ( op ) 1782 switch ( op )
1850 const char *mnemonic; 1845 const char *mnemonic;
1851 char type_char = 0; 1846 char type_char = 0;
1852 bool use_star; 1847 bool use_star;
1853 AsmArgMode mode; 1848 AsmArgMode mode;
1854 1849
1855 insnTemplate = new OutBuffer; 1850 insnTemplate.str("");
1856 // %% todo: special case for something.. 1851 // %% todo: special case for something..
1857 if ( opInfo->linkType == Out_Mnemonic ) 1852 if ( opInfo->linkType == Out_Mnemonic )
1858 mnemonic = alternateMnemonics[opInfo->link]; 1853 mnemonic = alternateMnemonics[opInfo->link];
1859 else 1854 else
1860 mnemonic = opIdent->string; 1855 mnemonic = opIdent->string;
1919 } 1914 }
1920 } 1915 }
1921 else if ( op == Op_Branch ) 1916 else if ( op == Op_Branch )
1922 { 1917 {
1923 if ( operands[0].dataSize == Far_Ptr ) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that.. 1918 if ( operands[0].dataSize == Far_Ptr ) // %% type=Far_Ptr not set by Seg:Ofss OTOH, we don't support that..
1924 insnTemplate->writebyte ( 'l' ); 1919 insnTemplate << 'l';
1925 } 1920 }
1926 else if ( op == Op_fxch || op == Op_FfdRR_P || op == Op_FidR_P ) 1921 else if ( op == Op_fxch || op == Op_FfdRR_P || op == Op_FidR_P )
1927 { 1922 {
1928 if ( operands[0].cls == Opr_Mem && op == Op_FidR_P ) 1923 if ( operands[0].cls == Opr_Mem && op == Op_FidR_P )
1929 { 1924 {
1957 { 1952 {
1958 case Op_SizedStack: 1953 case Op_SizedStack:
1959 { 1954 {
1960 int mlen = strlen ( mnemonic ); 1955 int mlen = strlen ( mnemonic );
1961 if ( mnemonic[mlen-1] == 'd' ) 1956 if ( mnemonic[mlen-1] == 'd' )
1962 insnTemplate->write ( mnemonic, mlen-1 ); 1957 insnTemplate.write(mnemonic, mlen-1);
1963 else 1958 else
1964 { 1959 {
1965 insnTemplate->writestring ( ( char* ) mnemonic ); 1960 insnTemplate << mnemonic << 'w';
1966 insnTemplate->writebyte ( 'w' );
1967 } 1961 }
1968 } 1962 }
1969 break; 1963 break;
1970 case Op_cmpsd: 1964 case Op_cmpsd:
1971 case Op_insX: 1965 case Op_insX:
1976 case Op_stosX: 1970 case Op_stosX:
1977 { 1971 {
1978 int mlen = strlen ( mnemonic ); 1972 int mlen = strlen ( mnemonic );
1979 if ( mnemonic[mlen-1] == 'd' ) 1973 if ( mnemonic[mlen-1] == 'd' )
1980 { 1974 {
1981 insnTemplate->write ( mnemonic, mlen-1 ); 1975 insnTemplate.write(mnemonic, mlen-1) << 'l';
1982 insnTemplate->writebyte ( 'l' );
1983 } 1976 }
1984 else 1977 else
1985 { 1978 {
1986 insnTemplate->writestring ( ( char* ) mnemonic ); 1979 insnTemplate << mnemonic;
1987 } 1980 }
1988 } 1981 }
1989 break; 1982 break;
1990 case Op_movsx: 1983 case Op_movsx:
1991 case Op_movzx: 1984 case Op_movzx:
2008 default: 2001 default:
2009 stmt->error ( "invalid operand size/type" ); 2002 stmt->error ( "invalid operand size/type" );
2010 return false; 2003 return false;
2011 } 2004 }
2012 assert ( type_char != 0 ); 2005 assert ( type_char != 0 );
2013 insnTemplate->write ( mnemonic, mlen-1 ); 2006 insnTemplate.write(mnemonic, mlen-1) << tc_1 << type_char;
2014 insnTemplate->writebyte ( tc_1 );
2015 insnTemplate->writebyte ( type_char );
2016 } 2007 }
2017 break; 2008 break;
2018 default: 2009 default:
2019 insnTemplate->writestring ( ( char* ) mnemonic ); 2010 insnTemplate << mnemonic;
2020 if ( type_char ) 2011 if ( type_char )
2021 insnTemplate->writebyte ( type_char ); 2012 insnTemplate << type_char;
2022 break; 2013 break;
2023 } 2014 }
2024 2015
2025 switch ( opInfo->implicitClobbers & Clb_DXAX_Mask ) 2016 switch ( opInfo->implicitClobbers & Clb_DXAX_Mask )
2026 { 2017 {
2070 asmcode->regs[Reg_EBX] = true; 2061 asmcode->regs[Reg_EBX] = true;
2071 asmcode->regs[Reg_ECX] = true; 2062 asmcode->regs[Reg_ECX] = true;
2072 asmcode->regs[Reg_EDX] = true; 2063 asmcode->regs[Reg_EDX] = true;
2073 } 2064 }
2074 2065
2075 insnTemplate->writebyte ( ' ' ); 2066 insnTemplate << ' ';
2076 for ( int i__ = 0; i__ < nOperands; i__++ ) 2067 for ( int i__ = 0; i__ < nOperands; i__++ )
2077 { 2068 {
2078 int i; 2069 int i;
2079 if ( i__ != 0 ) 2070 if ( i__ != 0 )
2080 insnTemplate->writestring ( ( char* ) ", " ); 2071 insnTemplate << ", ";
2081 2072
2082 fmt = "$"; 2073 fmt = "$";
2083 2074
2084 switch ( op ) 2075 switch ( op )
2085 { 2076 {
2123 // handle __LOCAL_SIZE, which in this constant, is an immediate 2114 // handle __LOCAL_SIZE, which in this constant, is an immediate
2124 // should do this in slotexp.. 2115 // should do this in slotexp..
2125 addOperand ( "$", Arg_LocalSize, 2116 addOperand ( "$", Arg_LocalSize,
2126 ( Expression * ) operand->symbolDisplacement.data[0], asmcode ); 2117 ( Expression * ) operand->symbolDisplacement.data[0], asmcode );
2127 if ( operand->constDisplacement ) 2118 if ( operand->constDisplacement )
2128 insnTemplate->writebyte ( '+' ); 2119 insnTemplate << '+';
2129 else 2120 else
2130 break; 2121 break;
2131 } 2122 }
2132 2123
2133 if ( operand->symbolDisplacement.dim ) 2124 if ( operand->symbolDisplacement.dim )
2136 addOperand ( "$", Arg_Pointer, 2127 addOperand ( "$", Arg_Pointer,
2137 ( Expression * ) operand->symbolDisplacement.data[0], 2128 ( Expression * ) operand->symbolDisplacement.data[0],
2138 asmcode ); 2129 asmcode );
2139 2130
2140 if ( operand->constDisplacement ) 2131 if ( operand->constDisplacement )
2141 insnTemplate->writebyte ( '+' ); 2132 insnTemplate << '+';
2142 else 2133 else
2143 // skip the addOperand(fmt, Arg_Integer...) below 2134 // skip the addOperand(fmt, Arg_Integer...) below
2144 break; 2135 break;
2145 } 2136 }
2146 addOperand ( fmt, Arg_Integer, newIntExp ( operand->constDisplacement ), asmcode ); 2137 addOperand ( fmt, Arg_Integer, newIntExp ( operand->constDisplacement ), asmcode );
2153 { 2144 {
2154 asmcode->regs[clbr_reg] = true; 2145 asmcode->regs[clbr_reg] = true;
2155 } 2146 }
2156 } 2147 }
2157 if ( opTakesLabel() /*opInfo->takesLabel()*/ ) 2148 if ( opTakesLabel() /*opInfo->takesLabel()*/ )
2158 insnTemplate->writebyte ( '*' ); 2149 insnTemplate << '*';
2159 writeReg ( operand->reg ); 2150 writeReg ( operand->reg );
2160 /* 2151 /*
2161 insnTemplate->writestring("%"); 2152 insnTemplate << "%";
2162 insnTemplate->writestring(regInfo[operand->reg].name); 2153 insnTemplate << regInfo[operand->reg].name;
2163 */ 2154 */
2164 break; 2155 break;
2165 case Opr_Mem: 2156 case Opr_Mem:
2166 // better: use output operands for simple variable references 2157 // better: use output operands for simple variable references
2167 if ( ( opInfo->operands[i] & Opr_Update ) == Opr_Update ) 2158 if ( ( opInfo->operands[i] & Opr_Update ) == Opr_Update )
2181 2172
2182 if ( operand->segmentPrefix != Reg_Invalid || operand->constDisplacement ) 2173 if ( operand->segmentPrefix != Reg_Invalid || operand->constDisplacement )
2183 { 2174 {
2184 if ( operand->symbolDisplacement.dim ) 2175 if ( operand->symbolDisplacement.dim )
2185 { 2176 {
2186 insnTemplate->printf ( "%d", operand->constDisplacement ); 2177 insnTemplate << operand->constDisplacement << '+';
2187 insnTemplate->writebyte ( '+' );
2188 } 2178 }
2189 //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode); 2179 //addOperand(fmt, Arg_Integer, newIntExp(operand->constDisplacement), asmcode);
2190 if ( opInfo->operands[i] & Opr_Dest ) 2180 if ( opInfo->operands[i] & Opr_Dest )
2191 asmcode->clobbersMemory = 1; 2181 asmcode->clobbersMemory = 1;
2192 } 2182 }
2193 2183
2194 if ( operand->segmentPrefix != Reg_Invalid ) 2184 if ( operand->segmentPrefix != Reg_Invalid )
2195 { 2185 {
2196 writeReg ( operand->segmentPrefix ); 2186 writeReg ( operand->segmentPrefix );
2197 insnTemplate->writebyte ( ':' ); 2187 insnTemplate << ':';
2198 } 2188 }
2199 if ( operand->symbolDisplacement.dim ) 2189 if ( operand->symbolDisplacement.dim )
2200 { 2190 {
2201 Expression * e = ( Expression * ) operand->symbolDisplacement.data[0]; 2191 Expression * e = ( Expression * ) operand->symbolDisplacement.data[0];
2202 Declaration * decl = 0; 2192 Declaration * decl = 0;
2283 { 2273 {
2284 use_star = false; 2274 use_star = false;
2285 // simply write out the mangle 2275 // simply write out the mangle
2286 // on osx, prepend extra _ 2276 // on osx, prepend extra _
2287 if ( global.params.os == OSMacOSX ) 2277 if ( global.params.os == OSMacOSX )
2288 insnTemplate->writestring ( "_" ); 2278 insnTemplate << "_";
2289 insnTemplate->writestring ( decl->mangle() ); 2279 insnTemplate << decl->mangle();
2290 // addOperand2("${", ":c}", Arg_Pointer, e, asmcode); 2280 // addOperand2("${", ":c}", Arg_Pointer, e, asmcode);
2291 } 2281 }
2292 else 2282 else
2293 { 2283 {
2294 if ( use_star ) 2284 if ( use_star )
2295 { 2285 {
2296 insnTemplate->writebyte ( '*' ); 2286 insnTemplate << '*';
2297 use_star = false; 2287 use_star = false;
2298 } 2288 }
2299 2289
2300 if ( !sc->func->naked ) // no addrexp in naked asm please :) 2290 if ( !sc->func->naked ) // no addrexp in naked asm please :)
2301 { 2291 {
2307 addOperand ( fmt, Arg_Memory, e, asmcode, mode ); 2297 addOperand ( fmt, Arg_Memory, e, asmcode, mode );
2308 } 2298 }
2309 } 2299 }
2310 } 2300 }
2311 if ( use_star ) 2301 if ( use_star )
2312 insnTemplate->writebyte ( '*' ); 2302 insnTemplate << '*';
2313 if ( operand->segmentPrefix != Reg_Invalid && !(operand->constDisplacement)) 2303 if ( operand->segmentPrefix != Reg_Invalid && !(operand->constDisplacement))
2314 { 2304 {
2315 insnTemplate->printf ( "%d", operand->constDisplacement ); 2305 insnTemplate << operand->constDisplacement;
2316 if ( opInfo->operands[i] & Opr_Dest ) 2306 if ( opInfo->operands[i] & Opr_Dest )
2317 asmcode->clobbersMemory = 1; 2307 asmcode->clobbersMemory = 1;
2318 } 2308 }
2319 if ( operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid ) 2309 if ( operand->baseReg != Reg_Invalid || operand->indexReg != Reg_Invalid )
2320 { 2310 {
2321 insnTemplate->writebyte ( '(' ); 2311 insnTemplate << '(';
2322 if ( operand->baseReg != Reg_Invalid ) 2312 if ( operand->baseReg != Reg_Invalid )
2323 writeReg ( operand->baseReg ); 2313 writeReg ( operand->baseReg );
2324 if ( operand->indexReg != Reg_Invalid ) 2314 if ( operand->indexReg != Reg_Invalid )
2325 { 2315 {
2326 insnTemplate->writebyte ( ',' ); 2316 insnTemplate << ',';
2327 writeReg ( operand->indexReg ); 2317 writeReg ( operand->indexReg );
2328 if ( operand->scale ) 2318 if ( operand->scale )
2329 { 2319 {
2330 insnTemplate->printf ( ",%d", operand->scale ); 2320 insnTemplate << "," << operand->scale;
2331 } 2321 }
2332 } 2322 }
2333 insnTemplate->writebyte ( ')' ); 2323 insnTemplate << ')';
2334 if ( opInfo->operands[i] & Opr_Dest ) 2324 if ( opInfo->operands[i] & Opr_Dest )
2335 asmcode->clobbersMemory = 1; 2325 asmcode->clobbersMemory = 1;
2336 } 2326 }
2337 break; 2327 break;
2338 case Opr_Invalid: 2328 case Opr_Invalid:
2339 return false; 2329 return false;
2340 } 2330 }
2341 } 2331 }
2342 2332
2343 asmcode->insnTemplateLen = insnTemplate->offset; 2333 asmcode->insnTemplate = insnTemplate.str();
2344 asmcode->insnTemplate = ( char* ) insnTemplate->extractData();
2345 return true; 2334 return true;
2346 } 2335 }
2347 2336
2348 bool isIntExp ( Expression * exp ) 2337 bool isIntExp ( Expression * exp )
2349 { 2338 {
3014 if ( ( align & ( align - 1 ) ) == 0 ) 3003 if ( ( align & ( align - 1 ) ) == 0 )
3015 { 3004 {
3016 //FIXME: This printf is not portable. The use of `align` varies from system to system; 3005 //FIXME: This printf is not portable. The use of `align` varies from system to system;
3017 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary 3006 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary
3018 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 3007 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
3019 insnTemplate->printf ( ".balign\t%u", ( unsigned ) align ); 3008 insnTemplate << ".balign\t" << align;
3020 #else 3009 #else
3021 insnTemplate->printf ( ".align\t%u", ( unsigned ) align ); 3010 insnTemplate << ".align\t" << align;
3022 #endif 3011 #endif
3023 } 3012 }
3024 else 3013 else
3025 { 3014 {
3026 stmt->error ( "alignment must be a power of 2, not %u", ( unsigned ) align ); 3015 stmt->error ( "alignment must be a power of 2, not %u", ( unsigned ) align );
3031 3020
3032 void doEven() 3021 void doEven()
3033 { 3022 {
3034 // .align for GAS is in bits, others probably use bytes.. 3023 // .align for GAS is in bits, others probably use bytes..
3035 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN 3024 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
3036 insnTemplate->writestring ( ( char * ) ".align\t2" ); 3025 insnTemplate << ".align\t2";
3037 #else 3026 #else
3038 insnTemplate->writestring ( ( char * ) ".align\t2" ); 3027 insnTemplate << ".align\t2";
3039 #endif 3028 #endif
3040 setAsmCode(); 3029 setAsmCode();
3041 } 3030 }
3042 3031
3043 void doNaked() 3032 void doNaked()