mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 21:21:48 +03:00
get switch statements to work (#21159)
This commit is contained in:
parent
8bce4f5a1a
commit
63ed7154b7
4 changed files with 60 additions and 24 deletions
|
@ -1600,6 +1600,7 @@ void assignaddrc(code* c)
|
||||||
case FL.code:
|
case FL.code:
|
||||||
case FL.unde:
|
case FL.unde:
|
||||||
case FL.block:
|
case FL.block:
|
||||||
|
case FL.switch_:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1406,7 +1406,7 @@ void cdcnvt(ref CGstate cg, ref CodeBuilder cdb,elem* e, ref regm_t pretregs)
|
||||||
case OPu64_d: // ucvtf d31,x0
|
case OPu64_d: // ucvtf d31,x0
|
||||||
regm_t retregs1 = ALLREGS;
|
regm_t retregs1 = ALLREGS;
|
||||||
codelem(cgstate,cdb,e.E1,retregs1,false);
|
codelem(cgstate,cdb,e.E1,retregs1,false);
|
||||||
reg_t Rn = findreg(retregs1); // source integer register
|
reg_t Rn = findreg(retregs1); // source integer register
|
||||||
|
|
||||||
regm_t retregs = INSTR.FLOATREGS;
|
regm_t retregs = INSTR.FLOATREGS;
|
||||||
const tym = tybasic(e.Ety);
|
const tym = tybasic(e.Ety);
|
||||||
|
|
|
@ -2252,16 +2252,20 @@ void disassemble(uint c) @trusted
|
||||||
case ldr(1,0,3): p1 = "ldrsh"; goto Lldr;
|
case ldr(1,0,3): p1 = "ldrsh"; goto Lldr;
|
||||||
case ldr(2,0,0): p1 = "str"; goto Lldr;
|
case ldr(2,0,0): p1 = "str"; goto Lldr;
|
||||||
case ldr(2,0,1): p1 = "ldr"; goto Lldr;
|
case ldr(2,0,1): p1 = "ldr"; goto Lldr;
|
||||||
case ldr(2,0,2): p1 = "ldrsw"; goto Lldr64;
|
case ldr(2,0,2): p1 = "ldrsw"; goto Lldrsw;
|
||||||
case ldr(3,0,0): p1 = "str"; goto Lldr64;
|
case ldr(3,0,0): p1 = "str"; goto Lldr64;
|
||||||
case ldr(3,0,1): p1 = "ldr"; goto Lldr64;
|
case ldr(3,0,1): p1 = "ldr"; goto Lldr64;
|
||||||
//case ldr(3,0,2): p1 = "prfm";
|
//case ldr(3,0,2): p1 = "prfm";
|
||||||
|
Lldrsw:
|
||||||
|
p2 = regString(true, Rt);
|
||||||
|
p3 = eaString(0, cast(ubyte)Rn, imm12 * 4);
|
||||||
|
break;
|
||||||
|
|
||||||
Lldr64:
|
Lldr64:
|
||||||
is64 = true;
|
is64 = true;
|
||||||
Lldr:
|
Lldr:
|
||||||
p2 = regString(is64, Rt);
|
p2 = regString(is64, Rt);
|
||||||
uint offset = imm12 * (is64 ? 8 : 4);
|
p3 = eaString(0, cast(ubyte)Rn, imm12 * (is64 ? 8 : 4));
|
||||||
p3 = eaString(0, cast(ubyte)Rn, offset);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ldr(0,1,0): p1 = "str"; goto LsimdFp;
|
case ldr(0,1,0): p1 = "str"; goto LsimdFp;
|
||||||
|
|
|
@ -937,7 +937,7 @@ void outblkexitcode(ref CodeBuilder cdb, block* bl, ref int anyspill, const(FL)*
|
||||||
case BC.switch_:
|
case BC.switch_:
|
||||||
{
|
{
|
||||||
assert(!(bl.Bflags & BFL.epilog));
|
assert(!(bl.Bflags & BFL.epilog));
|
||||||
doswitch(cdb,bl); // hide messy details
|
doswitch(cgstate,cdb,bl); // hide messy details
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BC.jcatch: // D catch clause of try-catch
|
case BC.jcatch: // D catch clause of try-catch
|
||||||
|
@ -1598,9 +1598,20 @@ struct CaseVal
|
||||||
* Generate comparison of [reg2,reg] with val
|
* Generate comparison of [reg2,reg] with val
|
||||||
*/
|
*/
|
||||||
@trusted
|
@trusted
|
||||||
private void cmpval(ref CodeBuilder cdb, targ_llong val, uint sz, reg_t reg, reg_t reg2, reg_t sreg)
|
private void cmpval(CGstate cg, ref CodeBuilder cdb, targ_llong val, uint sz, reg_t reg, reg_t reg2, reg_t sreg)
|
||||||
{
|
{
|
||||||
if (I64 && sz == 8)
|
if (cg.AArch64)
|
||||||
|
{
|
||||||
|
// TODO AArch64 use CMP https://www.scs.stanford.edu/~zyedidia/arm64/cmp_subs_addsub_imm.html
|
||||||
|
assert(sreg == NOREG);
|
||||||
|
regm_t retregs = cg.allregs & ~mask(reg);
|
||||||
|
sreg = allocreg(cdb,retregs,TYint);
|
||||||
|
movregconst(cdb,sreg,val,sz == 8 ? 64 : 0);
|
||||||
|
getregsNoSave(retregs);
|
||||||
|
assert(reg2 == NOREG);
|
||||||
|
cdb.gen1(INSTR.cmp_shift(sz == 8, reg, 0, 0, sreg)); // CMP sreg,reg
|
||||||
|
}
|
||||||
|
else if (I64 && sz == 8)
|
||||||
{
|
{
|
||||||
assert(reg2 == NOREG);
|
assert(reg2 == NOREG);
|
||||||
if (val == cast(int)val) // if val is a 64 bit value sign-extended from 32 bits
|
if (val == cast(int)val) // if val is a 64 bit value sign-extended from 32 bits
|
||||||
|
@ -1630,7 +1641,7 @@ private void cmpval(ref CodeBuilder cdb, targ_llong val, uint sz, reg_t reg, reg
|
||||||
}
|
}
|
||||||
|
|
||||||
@trusted extern (D)
|
@trusted extern (D)
|
||||||
private void ifthen(ref CodeBuilder cdb, scope CaseVal[] casevals,
|
private void ifthen(CGstate cg, ref CodeBuilder cdb, scope CaseVal[] casevals,
|
||||||
uint sz, reg_t reg, reg_t reg2, reg_t sreg, block* bdefault, bool last)
|
uint sz, reg_t reg, reg_t reg2, reg_t sreg, block* bdefault, bool last)
|
||||||
{
|
{
|
||||||
const ncases = casevals.length;
|
const ncases = casevals.length;
|
||||||
|
@ -1640,18 +1651,27 @@ private void ifthen(ref CodeBuilder cdb, scope CaseVal[] casevals,
|
||||||
|
|
||||||
// Compares for casevals[0..pivot]
|
// Compares for casevals[0..pivot]
|
||||||
CodeBuilder cdb1; cdb1.ctor();
|
CodeBuilder cdb1; cdb1.ctor();
|
||||||
ifthen(cdb1, casevals[0 .. pivot], sz, reg, reg2, sreg, bdefault, true);
|
ifthen(cg, cdb1, casevals[0 .. pivot], sz, reg, reg2, sreg, bdefault, true);
|
||||||
|
|
||||||
// Compares for casevals[pivot+1..ncases]
|
// Compares for casevals[pivot+1..ncases]
|
||||||
CodeBuilder cdb2; cdb2.ctor();
|
CodeBuilder cdb2; cdb2.ctor();
|
||||||
ifthen(cdb2, casevals[pivot + 1 .. $], sz, reg, reg2, sreg, bdefault, last);
|
ifthen(cg, cdb2, casevals[pivot + 1 .. $], sz, reg, reg2, sreg, bdefault, last);
|
||||||
code* c2 = gennop(null);
|
code* c2 = gennop(null);
|
||||||
|
|
||||||
// Compare for caseval[pivot]
|
// Compare for caseval[pivot]
|
||||||
cmpval(cdb, casevals[pivot].val, sz, reg, reg2, sreg);
|
cmpval(cg, cdb, casevals[pivot].val, sz, reg, reg2, sreg);
|
||||||
genjmp(cdb,JE,FL.block,casevals[pivot].target); // JE target
|
if (cg.AArch64)
|
||||||
// Note uint jump here, as cases were sorted using uint comparisons
|
{
|
||||||
genjmp(cdb,JA,FL.code,cast(block*) c2); // JG c2
|
genBranch(cdb,COND.eq,FL.block,casevals[pivot].target); // equal
|
||||||
|
// Note uint jump here, as cases were sorted using uint comparisons
|
||||||
|
genBranch(cdb,COND.cs,FL.code,cast(block*) c2); // greater than
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genjmp(cdb,JE,FL.block,casevals[pivot].target); // JE target
|
||||||
|
// Note uint jump here, as cases were sorted using uint comparisons
|
||||||
|
genjmp(cdb,JA,FL.code,cast(block*) c2); // JG c2
|
||||||
|
}
|
||||||
|
|
||||||
cdb.append(cdb1);
|
cdb.append(cdb1);
|
||||||
cdb.append(c2);
|
cdb.append(c2);
|
||||||
|
@ -1662,20 +1682,29 @@ private void ifthen(ref CodeBuilder cdb, scope CaseVal[] casevals,
|
||||||
foreach (size_t n; 0 .. ncases)
|
foreach (size_t n; 0 .. ncases)
|
||||||
{
|
{
|
||||||
targ_llong val = casevals[n].val;
|
targ_llong val = casevals[n].val;
|
||||||
cmpval(cdb, val, sz, reg, reg2, sreg);
|
cmpval(cg, cdb, val, sz, reg, reg2, sreg);
|
||||||
code* cnext = null;
|
code* cnext = null;
|
||||||
if (reg2 != NOREG)
|
if (reg2 != NOREG)
|
||||||
{
|
{
|
||||||
|
assert(!cg.AArch64);
|
||||||
cnext = gennop(null);
|
cnext = gennop(null);
|
||||||
genjmp(cdb,JNE,FL.code,cast(block*) cnext); // JNE cnext
|
genjmp(cdb,JNE,FL.code,cast(block*) cnext); // JNE cnext
|
||||||
cdb.genc2(0x81,modregrm(3,7,reg2),cast(targ_size_t)MSREG(val)); // CMP reg2,MSREG(casevalue)
|
cdb.genc2(0x81,modregrm(3,7,reg2),cast(targ_size_t)MSREG(val)); // CMP reg2,MSREG(casevalue)
|
||||||
}
|
}
|
||||||
genjmp(cdb,JE,FL.block,casevals[n].target); // JE caseaddr
|
if (cg.AArch64)
|
||||||
|
genBranch(cdb,COND.eq,FL.block,casevals[n].target); // JE caseaddr
|
||||||
|
else
|
||||||
|
genjmp(cdb,JE,FL.block,casevals[n].target); // JE caseaddr
|
||||||
cdb.append(cnext);
|
cdb.append(cnext);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last) // if default is not next block
|
if (last) // if default is not next block
|
||||||
genjmp(cdb,JMP,FL.block,bdefault);
|
{
|
||||||
|
if (cg.AArch64)
|
||||||
|
genBranch(cdb,COND.al,FL.block,bdefault);
|
||||||
|
else
|
||||||
|
genjmp(cdb,JMP,FL.block,bdefault);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1688,7 +1717,7 @@ private void ifthen(ref CodeBuilder cdb, scope CaseVal[] casevals,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@trusted
|
@trusted
|
||||||
void doswitch(ref CodeBuilder cdb, block* b)
|
void doswitch(ref CGstate cg, ref CodeBuilder cdb, block* b)
|
||||||
{
|
{
|
||||||
// If switch tables are in code segment and we need a CS: override to get at them
|
// If switch tables are in code segment and we need a CS: override to get at them
|
||||||
bool csseg = cast(bool)(config.flags & CFGromable);
|
bool csseg = cast(bool)(config.flags & CFGromable);
|
||||||
|
@ -1732,7 +1761,7 @@ void doswitch(ref CodeBuilder cdb, block* b)
|
||||||
/* Three kinds of switch strategies - pick one
|
/* Three kinds of switch strategies - pick one
|
||||||
*/
|
*/
|
||||||
const ncases = b.Bswitch.length;
|
const ncases = b.Bswitch.length;
|
||||||
if (ncases <= 3)
|
if (ncases <= 3 || cg.AArch64)
|
||||||
goto Lifthen;
|
goto Lifthen;
|
||||||
else if (I16 && cast(targ_ullong)(vmax - vmin) <= ncases * 2)
|
else if (I16 && cast(targ_ullong)(vmax - vmin) <= ncases * 2)
|
||||||
goto Ljmptab; // >=50% of the table is case values, rest is default
|
goto Ljmptab; // >=50% of the table is case values, rest is default
|
||||||
|
@ -1748,7 +1777,8 @@ void doswitch(ref CodeBuilder cdb, block* b)
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
{ // generate if-then sequence
|
{ // generate if-then sequence
|
||||||
Lifthen:
|
Lifthen:
|
||||||
regm_t retregs = ALLREGS;
|
//printf("ifthen:\n");
|
||||||
|
regm_t retregs = cg.allregs;
|
||||||
b.bc = BC.ifthen;
|
b.bc = BC.ifthen;
|
||||||
scodelem(cgstate,cdb,e,retregs,0,true);
|
scodelem(cgstate,cdb,e,retregs,0,true);
|
||||||
reg_t reg, reg2;
|
reg_t reg, reg2;
|
||||||
|
@ -1786,8 +1816,8 @@ void doswitch(ref CodeBuilder cdb, block* b)
|
||||||
casevals[n].target = list_block(bl);
|
casevals[n].target = list_block(bl);
|
||||||
|
|
||||||
// See if we need a scratch register
|
// See if we need a scratch register
|
||||||
if (sreg == NOREG && I64 && sz == 8 && val != cast(int)val)
|
if (!cg.AArch64 && sreg == NOREG && I64 && sz == 8 && val != cast(int)val)
|
||||||
{ regm_t regm = ALLREGS & ~mask(reg);
|
{ regm_t regm = cg.allregs & ~mask(reg);
|
||||||
sreg = allocreg(cdb,regm, TYint);
|
sreg = allocreg(cdb,regm, TYint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1799,7 +1829,7 @@ void doswitch(ref CodeBuilder cdb, block* b)
|
||||||
//printf("casevals[%lld] = x%x\n", n, casevals[n].val);
|
//printf("casevals[%lld] = x%x\n", n, casevals[n].val);
|
||||||
|
|
||||||
// Generate binary tree of comparisons
|
// Generate binary tree of comparisons
|
||||||
ifthen(cdb, casevals, sz, reg, reg2, sreg, bdefault, bdefault != b.Bnext);
|
ifthen(cg, cdb, casevals, sz, reg, reg2, sreg, bdefault, bdefault != b.Bnext);
|
||||||
|
|
||||||
cgstate.stackclean--;
|
cgstate.stackclean--;
|
||||||
return;
|
return;
|
||||||
|
@ -1809,7 +1839,7 @@ void doswitch(ref CodeBuilder cdb, block* b)
|
||||||
{
|
{
|
||||||
// Use switch value to index into jump table
|
// Use switch value to index into jump table
|
||||||
Ljmptab:
|
Ljmptab:
|
||||||
//printf("Ljmptab:\n");
|
//printf("jmptab:\n");
|
||||||
|
|
||||||
b.bc = BC.jmptab;
|
b.bc = BC.jmptab;
|
||||||
|
|
||||||
|
@ -2013,6 +2043,7 @@ else
|
||||||
* Note that it has not been tested with MACHOBJ (OSX).
|
* Note that it has not been tested with MACHOBJ (OSX).
|
||||||
*/
|
*/
|
||||||
Lswitch:
|
Lswitch:
|
||||||
|
//printf("repne scasw:\n");
|
||||||
regm_t retregs = mAX; // SCASW requires AX
|
regm_t retregs = mAX; // SCASW requires AX
|
||||||
if (dword)
|
if (dword)
|
||||||
retregs |= mDX;
|
retregs |= mDX;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue