Mercurial > projects > ldc
comparison gen/asm-x86-64.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 |
---|---|
1527 stmt->error("wrong operand types"); | 1527 stmt->error("wrong operand types"); |
1528 return false; | 1528 return false; |
1529 } | 1529 } |
1530 | 1530 |
1531 void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { | 1531 void addOperand(const char * fmt, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { |
1532 insnTemplate->writestring((char*) fmt); | 1532 if (sc->func->naked) |
1533 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); | 1533 { |
1534 asmcode->args.push( new AsmArg(type, e, mode) ); | 1534 switch(type) |
1535 { | |
1536 case Arg_Integer: | |
1537 if (e->type->isunsigned()) | |
1538 insnTemplate->printf("$%llu", e->toUInteger()); | |
1539 else | |
1540 insnTemplate->printf("$%lld", e->toInteger()); | |
1541 break; | |
1542 | |
1543 case Arg_Pointer: | |
1544 stmt->error("unsupported pointer reference to '%s' in naked asm", e->toChars()); | |
1545 break; | |
1546 | |
1547 case Arg_Memory: | |
1548 if (e->op == TOKvar) | |
1549 { | |
1550 VarExp* v = (VarExp*)e; | |
1551 if (VarDeclaration* vd = v->var->isVarDeclaration()) | |
1552 { | |
1553 if (!vd->isDataseg()) | |
1554 { | |
1555 stmt->error("only global variables can be referenced by identifier in naked asm"); | |
1556 break; | |
1557 } | |
1558 | |
1559 // print out the mangle | |
1560 insnTemplate->writestring(vd->mangle()); | |
1561 vd->nakedUse = true; | |
1562 break; | |
1563 } | |
1564 } | |
1565 stmt->error("unsupported memory reference to '%s' in naked asm", e->toChars()); | |
1566 break; | |
1567 | |
1568 default: | |
1569 assert(0 && "asm unsupported arg"); | |
1570 break; | |
1571 } | |
1572 } | |
1573 else | |
1574 { | |
1575 insnTemplate->writestring((char*) fmt); | |
1576 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); | |
1577 asmcode->args.push( new AsmArg(type, e, mode) ); | |
1578 } | |
1535 } | 1579 } |
1536 void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { | 1580 void addOperand2(const char * fmtpre, const char * fmtpost, AsmArgType type, Expression * e, AsmCode * asmcode, AsmArgMode mode = Mode_Input) { |
1537 insnTemplate->writestring((char*) fmtpre); | 1581 assert(!sc->func->naked); |
1538 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); | 1582 insnTemplate->writestring((char*) fmtpre); |
1539 insnTemplate->writestring((char*) fmtpost); | 1583 insnTemplate->printf("<<%s%d>>", (mode==Mode_Input)?"in":"out", asmcode->args.dim); |
1540 asmcode->args.push( new AsmArg(type, e, mode) ); | 1584 insnTemplate->writestring((char*) fmtpost); |
1585 asmcode->args.push( new AsmArg(type, e, mode) ); | |
1541 } | 1586 } |
1542 | 1587 |
1543 void addLabel(char* id) { | 1588 void addLabel(char* id) { |
1544 insnTemplate->writestring(sc->func->mangle()); | 1589 insnTemplate->writestring(sc->func->mangle()); |
1545 insnTemplate->writestring("_"); | 1590 insnTemplate->writestring("_"); |
1546 insnTemplate->writestring(id); | 1591 insnTemplate->writestring(id); |
1547 } | 1592 } |
1548 | 1593 |
1549 /* Determines whether the operand is a register, memory reference | 1594 /* Determines whether the operand is a register, memory reference |
1550 or immediate. Immediate addresses are currently classified as | 1595 or immediate. Immediate addresses are currently classified as |
1551 memory. This function is called before the exact instructions | 1596 memory. This function is called before the exact instructions |
2035 } else { | 2080 } else { |
2036 if (use_star) { | 2081 if (use_star) { |
2037 insnTemplate->writebyte('*'); | 2082 insnTemplate->writebyte('*'); |
2038 use_star = false; | 2083 use_star = false; |
2039 } | 2084 } |
2085 | |
2086 if (!sc->func->naked) { // no addrexp in naked asm please :) | |
2040 Type* tt = e->type->pointerTo(); | 2087 Type* tt = e->type->pointerTo(); |
2041 e = new AddrExp(0, e); | 2088 e = new AddrExp(0, e); |
2042 e->type = tt; | 2089 e->type = tt; |
2090 } | |
2043 | 2091 |
2044 addOperand(fmt, Arg_Memory, e, asmcode, mode); | 2092 addOperand(fmt, Arg_Memory, e, asmcode, mode); |
2045 } | 2093 } |
2046 } | 2094 } |
2047 } | 2095 } |
2634 // apparently a.out platforms use bits instead of bytes... | 2682 // apparently a.out platforms use bits instead of bytes... |
2635 | 2683 |
2636 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2' | 2684 // parse primary: DMD allows 'MyAlign' (const int) but not '2+2' |
2637 // GAS is padding with NOPs last time I checked. | 2685 // GAS is padding with NOPs last time I checked. |
2638 Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret); | 2686 Expression * e = parseAsmExp()->optimize(WANTvalue | WANTinterpret); |
2639 integer_t align = e->toInteger(); | 2687 uinteger_t align = e->toUInteger(); |
2640 | 2688 |
2641 if (align & align - 1 == 0) { | 2689 if ((align & (align - 1)) == 0) { |
2642 //FIXME: This printf is not portable. The use of `align` varies from system to system; | 2690 //FIXME: This printf is not portable. The use of `align` varies from system to system; |
2643 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary | 2691 // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary |
2644 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN | 2692 #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN |
2645 insnTemplate->printf(".balign\t%u", (unsigned) align); | 2693 insnTemplate->printf(".balign\t%u", (unsigned) align); |
2646 #else | 2694 #else |
2647 insnTemplate->printf(".align\t%u", (unsigned) align); | 2695 insnTemplate->printf(".align\t%u", (unsigned) align); |
2648 #endif | 2696 #endif |
2649 } else { | 2697 } else { |
2650 stmt->error("alignment must be a power of 2"); | 2698 stmt->error("alignment must be a power of 2, not %u", (unsigned) align); |
2651 } | 2699 } |
2652 | 2700 |
2653 setAsmCode(); | 2701 setAsmCode(); |
2654 } | 2702 } |
2655 | 2703 |