Mercurial > projects > ldc
comparison gen/asm-x86-32.h @ 920:545f54041d91
Implemented proper support for naked asm using llvm module level asm. Still not 100% complete, but already 1000 times better that what we had before. Don's BignumX86 implementation from Tango (when turned into a standalone unittest) seems to fully work with no changes, and great performance :)
Fixed align N; in asm blocks.
Fixed inreg parameter passing on x86 for ref/out params.
Removed support for lazy initialization of function local static variables, I have no idea why I ever implemented this, it's not in the D spec, and DMD doesn't support it :P
Some of the global variable related changes might cause minor regressions, but they should be easily fixable.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 03 Feb 2009 08:54:57 +0100 |
parents | e70a0e7e2260 |
children | 0ea8bdfe4405 |
comparison
equal
deleted
inserted
replaced
919:c76f74d09fb1 | 920:545f54041d91 |
---|---|
1407 stmt->error("wrong operand types"); | 1407 stmt->error("wrong operand types"); |
1408 return false; | 1408 return false; |
1409 } | 1409 } |
1410 | 1410 |
1411 void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { | 1411 void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { |
1412 insnTemplate->writestring((char*) fmt); | 1412 if (sc->func->naked) |
1413 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); | 1413 { |
1414 asmcode->args.push( new AsmArg(type, e, mode) ); | 1414 switch(type) |
1415 { | |
1416 case Arg_Integer: | |
1417 if (e->type->isunsigned()) | |
1418 insnTemplate->printf("$%llu", e->toUInteger()); | |
1419 else | |
1420 insnTemplate->printf("$%lld", e->toInteger()); | |
1421 break; | |
1422 | |
1423 case Arg_Pointer: | |
1424 stmt->error("unsupported pointer reference to '%s' in naked asm", e->toChars()); | |
1425 break; | |
1426 | |
1427 case Arg_Memory: | |
1428 if (e->op == TOKvar) | |
1429 { | |
1430 VarExp* v = (VarExp*)e; | |
1431 if (VarDeclaration* vd = v->var->isVarDeclaration()) | |
1432 { | |
1433 if (!vd->isDataseg()) | |
1434 { | |
1435 stmt->error("only global variables can be referenced by identifier in naked asm"); | |
1436 break; | |
1437 } | |
1438 | |
1439 // print out the mangle | |
1440 insnTemplate->writestring(vd->mangle()); | |
1441 vd->nakedUse = true; | |
1442 break; | |
1443 } | |
1444 } | |
1445 stmt->error("unsupported memory reference to '%s' in naked asm", e->toChars()); | |
1446 break; | |
1447 | |
1448 default: | |
1449 assert(0 && "asm unsupported arg"); | |
1450 break; | |
1451 } | |
1452 } | |
1453 else | |
1454 { | |
1455 insnTemplate->writestring((char*) fmt); | |
1456 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); | |
1457 asmcode->args.push( new AsmArg(type, e, mode) ); | |
1458 } | |
1415 } | 1459 } |
1416 void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { | 1460 void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { |
1417 insnTemplate->writestring((char*) fmtpre); | 1461 assert(!sc->func->naked); |
1418 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); | 1462 insnTemplate->writestring((char*) fmtpre); |
1419 insnTemplate->writestring((char*) fmtpost); | 1463 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); |
1420 asmcode->args.push( new AsmArg(type, e, mode) ); | 1464 insnTemplate->writestring((char*) fmtpost); |
1465 asmcode->args.push( new AsmArg(type, e, mode) ); | |
1421 } | 1466 } |
1422 | 1467 |
1423 void addLabel(char* id) { | 1468 void addLabel(char* id) { |
1424 insnTemplate->writestring(sc->func->mangle()); | 1469 insnTemplate->writestring(sc->func->mangle()); |
1425 insnTemplate->writestring("_"); | 1470 insnTemplate->writestring("_"); |
1426 insnTemplate->writestring(id); | 1471 insnTemplate->writestring(id); |
1427 } | 1472 } |
1428 | 1473 |
1429 /* Determines whether the operand is a register, memory reference | 1474 /* Determines whether the operand is a register, memory reference |
1430 or immediate. Immediate addresses are currently classified as | 1475 or immediate. Immediate addresses are currently classified as |
1431 memory. This function is called before the exact instructions | 1476 memory. This function is called before the exact instructions |
1914 } else { | 1959 } else { |
1915 if (use_star) { | 1960 if (use_star) { |
1916 insnTemplate->writebyte('*'); | 1961 insnTemplate->writebyte('*'); |
1917 use_star = false; | 1962 use_star = false; |
1918 } | 1963 } |
1964 | |
1965 if (!sc->func->naked) { // no addrexp in naked asm please :) | |
1919 Type* tt = e->type->pointerTo(); | 1966 Type* tt = e->type->pointerTo(); |
1920 e = new AddrExp(0, e); | 1967 e = new AddrExp(0, e); |
1921 e->type = tt; | 1968 e->type = tt; |
1969 } | |
1922 | 1970 |
1923 addOperand(fmt, Arg_Memory, e, asmcode, mode); | 1971 addOperand(fmt, Arg_Memory, e, asmcode, mode); |
1924 } | 1972 } |
1925 } | 1973 } |
1926 } | 1974 } |
2513 // apparently a.out platforms use bits instead of bytes... | 2561 // apparently a.out platforms use bits instead of bytes... |
2514 | 2562 |
2515 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2' | 2563 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2' |
2516 // GAS is padding with NOPs last time I checked. | 2564 // GAS is padding with NOPs last time I checked. |
2517 Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret); | 2565 Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret); |
2518 integer_t align = e->toInteger(); | 2566 uinteger_t align = e->toUInteger(); |
2519 | 2567 |
2520 if (align & align - 1 == 0) { | 2568 if ((align & (align - 1)) == 0) { |
2521 //FIXME: This printf is not portable. The use of `align` varies from system to system; | 2569 //FIXME: This printf is not portable. The use of `align` varies from system to system; |
2522 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary | 2570 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary |
2523 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN | 2571 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN |
2524 insnTemplate->printf(".balign\t%u", (unsigned) align); | 2572 insnTemplate->printf(".balign\t%u", (unsigned) align); |
2525 #else | 2573 #else |
2526 insnTemplate->printf(".align\t%u", (unsigned) align); | 2574 insnTemplate->printf(".align\t%u", (unsigned) align); |
2527 #endif | 2575 #endif |
2528 } else { | 2576 } else { |
2529 stmt->error("alignment must be a power of 2"); | 2577 stmt->error("alignment must be a power of 2, not %u", (unsigned) align); |
2530 } | 2578 } |
2531 | 2579 |
2532 setAsmCode(); | 2580 setAsmCode(); |
2533 } | 2581 } |
2534 | 2582 |