mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-08 19:25:47 +00:00
Implement signed and unsigned division and remainder
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4508 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -59,15 +59,19 @@ namespace {
|
|||||||
void visitBranchInst(BranchInst &BI);
|
void visitBranchInst(BranchInst &BI);
|
||||||
|
|
||||||
// Arithmetic operators
|
// Arithmetic operators
|
||||||
|
void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
|
||||||
void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); }
|
void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); }
|
||||||
void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); }
|
void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); }
|
||||||
void visitMul(BinaryOperator &B);
|
void visitMul(BinaryOperator &B);
|
||||||
|
|
||||||
|
void visitDiv(BinaryOperator &B) { visitDivRem(B); }
|
||||||
|
void visitRem(BinaryOperator &B) { visitDivRem(B); }
|
||||||
|
void visitDivRem(BinaryOperator &B);
|
||||||
|
|
||||||
// Bitwise operators
|
// Bitwise operators
|
||||||
void visitAnd(BinaryOperator &B) { visitSimpleBinary(B, 2); }
|
void visitAnd(BinaryOperator &B) { visitSimpleBinary(B, 2); }
|
||||||
void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); }
|
void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); }
|
||||||
void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); }
|
void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); }
|
||||||
void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
|
|
||||||
|
|
||||||
// Binary comparison operators
|
// Binary comparison operators
|
||||||
|
|
||||||
@@ -247,7 +251,55 @@ void ISel::visitMul(BinaryOperator &I) {
|
|||||||
|
|
||||||
// Put the result into the destination register...
|
// Put the result into the destination register...
|
||||||
BuildMI(BB, MovOpcode[Class], 1, getReg(I)).addReg(Reg);
|
BuildMI(BB, MovOpcode[Class], 1, getReg(I)).addReg(Reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// visitDivRem - Handle division and remainder instructions... these
|
||||||
|
/// instruction both require the same instructions to be generated, they just
|
||||||
|
/// select the result from a different register. Note that both of these
|
||||||
|
/// instructions work differently for signed and unsigned operands.
|
||||||
|
///
|
||||||
|
void ISel::visitDivRem(BinaryOperator &I) {
|
||||||
|
unsigned Class = getClass(I.getType());
|
||||||
|
if (Class > 2) // FIXME: Handle longs
|
||||||
|
visitInstruction(I);
|
||||||
|
|
||||||
|
static const unsigned Regs[] ={ X86::AL , X86::AX , X86::EAX };
|
||||||
|
static const unsigned MovOpcode[]={ X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 };
|
||||||
|
static const unsigned ExtOpcode[]={ X86::CBW , X86::CWD , X86::CWQ };
|
||||||
|
static const unsigned ClrOpcode[]={ X86::XORrr8, X86::XORrr16, X86::XORrr32 };
|
||||||
|
static const unsigned ExtRegs[] ={ X86::AH , X86::DX , X86::EDX };
|
||||||
|
|
||||||
|
static const unsigned DivOpcode[][4] = {
|
||||||
|
{ X86::DIVrr8 , X86::DIVrr16 , X86::DIVrr32 , 0 }, // Unsigned division
|
||||||
|
{ X86::IDIVrr8, X86::IDIVrr16, X86::IDIVrr32, 0 }, // Signed division
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isSigned = I.getType()->isSigned();
|
||||||
|
unsigned Reg = Regs[Class];
|
||||||
|
unsigned ExtReg = ExtRegs[Class];
|
||||||
|
unsigned Op0Reg = getReg(I.getOperand(1));
|
||||||
|
unsigned Op1Reg = getReg(I.getOperand(1));
|
||||||
|
|
||||||
|
// Put the first operand into one of the A registers...
|
||||||
|
BuildMI(BB, MovOpcode[Class], 1, Reg).addReg(Op0Reg);
|
||||||
|
|
||||||
|
if (isSigned) {
|
||||||
|
// Emit a sign extension instruction...
|
||||||
|
BuildMI(BB, ExtOpcode[Class], 1, ExtReg).addReg(Reg);
|
||||||
|
} else {
|
||||||
|
// If unsigned, emit a zeroing instruction... (reg = xor reg, reg)
|
||||||
|
BuildMI(BB, ClrOpcode[Class], 2, ExtReg).addReg(ExtReg).addReg(ExtReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out which register we want to pick the result out of...
|
||||||
|
unsigned DestReg = (I.getOpcode() == Instruction::Div) ? Reg : ExtReg;
|
||||||
|
|
||||||
|
// Emit the appropriate multiple instruction...
|
||||||
|
// FIXME: We need to mark that this modified AH, DX, or EDX also!!
|
||||||
|
BuildMI(BB,DivOpcode[isSigned][Class], 2, DestReg).addReg(Reg).addReg(Op1Reg);
|
||||||
|
|
||||||
|
// Put the result into the destination register...
|
||||||
|
BuildMI(BB, MovOpcode[Class], 1, getReg(I)).addReg(DestReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here
|
/// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here
|
||||||
@@ -255,11 +307,9 @@ void ISel::visitMul(BinaryOperator &I) {
|
|||||||
/// shift values equal to 1. Even the general case is sort of special,
|
/// shift values equal to 1. Even the general case is sort of special,
|
||||||
/// because the shift amount has to be in CL, not just any old register.
|
/// because the shift amount has to be in CL, not just any old register.
|
||||||
///
|
///
|
||||||
void
|
void ISel::visitShiftInst (ShiftInst &I) {
|
||||||
ISel::visitShiftInst (ShiftInst & I)
|
unsigned Op0r = getReg (I.getOperand(0));
|
||||||
{
|
unsigned DestReg = getReg(I);
|
||||||
unsigned Op0r = getReg (I.getOperand (0));
|
|
||||||
unsigned DestReg = getReg (I);
|
|
||||||
bool isLeftShift = I.getOpcode() == Instruction::Shl;
|
bool isLeftShift = I.getOpcode() == Instruction::Shl;
|
||||||
bool isOperandSigned = I.getType()->isUnsigned();
|
bool isOperandSigned = I.getType()->isUnsigned();
|
||||||
unsigned OperandClass = getClass(I.getType());
|
unsigned OperandClass = getClass(I.getType());
|
||||||
|
@@ -59,15 +59,19 @@ namespace {
|
|||||||
void visitBranchInst(BranchInst &BI);
|
void visitBranchInst(BranchInst &BI);
|
||||||
|
|
||||||
// Arithmetic operators
|
// Arithmetic operators
|
||||||
|
void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
|
||||||
void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); }
|
void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); }
|
||||||
void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); }
|
void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); }
|
||||||
void visitMul(BinaryOperator &B);
|
void visitMul(BinaryOperator &B);
|
||||||
|
|
||||||
|
void visitDiv(BinaryOperator &B) { visitDivRem(B); }
|
||||||
|
void visitRem(BinaryOperator &B) { visitDivRem(B); }
|
||||||
|
void visitDivRem(BinaryOperator &B);
|
||||||
|
|
||||||
// Bitwise operators
|
// Bitwise operators
|
||||||
void visitAnd(BinaryOperator &B) { visitSimpleBinary(B, 2); }
|
void visitAnd(BinaryOperator &B) { visitSimpleBinary(B, 2); }
|
||||||
void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); }
|
void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); }
|
||||||
void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); }
|
void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); }
|
||||||
void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass);
|
|
||||||
|
|
||||||
// Binary comparison operators
|
// Binary comparison operators
|
||||||
|
|
||||||
@@ -247,7 +251,55 @@ void ISel::visitMul(BinaryOperator &I) {
|
|||||||
|
|
||||||
// Put the result into the destination register...
|
// Put the result into the destination register...
|
||||||
BuildMI(BB, MovOpcode[Class], 1, getReg(I)).addReg(Reg);
|
BuildMI(BB, MovOpcode[Class], 1, getReg(I)).addReg(Reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// visitDivRem - Handle division and remainder instructions... these
|
||||||
|
/// instruction both require the same instructions to be generated, they just
|
||||||
|
/// select the result from a different register. Note that both of these
|
||||||
|
/// instructions work differently for signed and unsigned operands.
|
||||||
|
///
|
||||||
|
void ISel::visitDivRem(BinaryOperator &I) {
|
||||||
|
unsigned Class = getClass(I.getType());
|
||||||
|
if (Class > 2) // FIXME: Handle longs
|
||||||
|
visitInstruction(I);
|
||||||
|
|
||||||
|
static const unsigned Regs[] ={ X86::AL , X86::AX , X86::EAX };
|
||||||
|
static const unsigned MovOpcode[]={ X86::MOVrr8, X86::MOVrr16, X86::MOVrr32 };
|
||||||
|
static const unsigned ExtOpcode[]={ X86::CBW , X86::CWD , X86::CWQ };
|
||||||
|
static const unsigned ClrOpcode[]={ X86::XORrr8, X86::XORrr16, X86::XORrr32 };
|
||||||
|
static const unsigned ExtRegs[] ={ X86::AH , X86::DX , X86::EDX };
|
||||||
|
|
||||||
|
static const unsigned DivOpcode[][4] = {
|
||||||
|
{ X86::DIVrr8 , X86::DIVrr16 , X86::DIVrr32 , 0 }, // Unsigned division
|
||||||
|
{ X86::IDIVrr8, X86::IDIVrr16, X86::IDIVrr32, 0 }, // Signed division
|
||||||
|
};
|
||||||
|
|
||||||
|
bool isSigned = I.getType()->isSigned();
|
||||||
|
unsigned Reg = Regs[Class];
|
||||||
|
unsigned ExtReg = ExtRegs[Class];
|
||||||
|
unsigned Op0Reg = getReg(I.getOperand(1));
|
||||||
|
unsigned Op1Reg = getReg(I.getOperand(1));
|
||||||
|
|
||||||
|
// Put the first operand into one of the A registers...
|
||||||
|
BuildMI(BB, MovOpcode[Class], 1, Reg).addReg(Op0Reg);
|
||||||
|
|
||||||
|
if (isSigned) {
|
||||||
|
// Emit a sign extension instruction...
|
||||||
|
BuildMI(BB, ExtOpcode[Class], 1, ExtReg).addReg(Reg);
|
||||||
|
} else {
|
||||||
|
// If unsigned, emit a zeroing instruction... (reg = xor reg, reg)
|
||||||
|
BuildMI(BB, ClrOpcode[Class], 2, ExtReg).addReg(ExtReg).addReg(ExtReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out which register we want to pick the result out of...
|
||||||
|
unsigned DestReg = (I.getOpcode() == Instruction::Div) ? Reg : ExtReg;
|
||||||
|
|
||||||
|
// Emit the appropriate multiple instruction...
|
||||||
|
// FIXME: We need to mark that this modified AH, DX, or EDX also!!
|
||||||
|
BuildMI(BB,DivOpcode[isSigned][Class], 2, DestReg).addReg(Reg).addReg(Op1Reg);
|
||||||
|
|
||||||
|
// Put the result into the destination register...
|
||||||
|
BuildMI(BB, MovOpcode[Class], 1, getReg(I)).addReg(DestReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here
|
/// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here
|
||||||
@@ -255,11 +307,9 @@ void ISel::visitMul(BinaryOperator &I) {
|
|||||||
/// shift values equal to 1. Even the general case is sort of special,
|
/// shift values equal to 1. Even the general case is sort of special,
|
||||||
/// because the shift amount has to be in CL, not just any old register.
|
/// because the shift amount has to be in CL, not just any old register.
|
||||||
///
|
///
|
||||||
void
|
void ISel::visitShiftInst (ShiftInst &I) {
|
||||||
ISel::visitShiftInst (ShiftInst & I)
|
unsigned Op0r = getReg (I.getOperand(0));
|
||||||
{
|
unsigned DestReg = getReg(I);
|
||||||
unsigned Op0r = getReg (I.getOperand (0));
|
|
||||||
unsigned DestReg = getReg (I);
|
|
||||||
bool isLeftShift = I.getOpcode() == Instruction::Shl;
|
bool isLeftShift = I.getOpcode() == Instruction::Shl;
|
||||||
bool isOperandSigned = I.getType()->isUnsigned();
|
bool isOperandSigned = I.getType()->isUnsigned();
|
||||||
unsigned OperandClass = getClass(I.getType());
|
unsigned OperandClass = getClass(I.getType());
|
||||||
|
@@ -56,6 +56,16 @@ I(MULrr8 , "mulb", 0, 0) // AX = AL*R8 F6/4
|
|||||||
I(MULrr16 , "mulw", 0, 0) // DX:AX= AX*R16 F7/4
|
I(MULrr16 , "mulw", 0, 0) // DX:AX= AX*R16 F7/4
|
||||||
I(MULrr32 , "mull", 0, 0) // ED:EA= EA*R32 F7/4
|
I(MULrr32 , "mull", 0, 0) // ED:EA= EA*R32 F7/4
|
||||||
|
|
||||||
|
// unsigned division/remainder
|
||||||
|
I(DIVrr8 , "divb", 0, 0) // AX/r8= AL&AH F6/6
|
||||||
|
I(DIVrr16 , "divw", 0, 0) // DA/r16=AX&DX F7/6
|
||||||
|
I(DIVrr32 , "divl", 0, 0) // DA/r32=EAX&DX F7/6
|
||||||
|
|
||||||
|
// signed division/remainder
|
||||||
|
I(IDIVrr8 , "idivb", 0, 0) // AX/r8= AL&AH F6/6
|
||||||
|
I(IDIVrr16 , "idivw", 0, 0) // DA/r16=AX&DX F7/6
|
||||||
|
I(IDIVrr32 , "idivl", 0, 0) // DA/r32=EAX&DX F7/6
|
||||||
|
|
||||||
|
|
||||||
// Logical operators
|
// Logical operators
|
||||||
I(ANDrr8 , "andb", 0, 0) // R8 &= R8 20/r
|
I(ANDrr8 , "andb", 0, 0) // R8 &= R8 20/r
|
||||||
@@ -88,5 +98,11 @@ I(SARir16 , "sarw", 0, 0) // R16 >>= imm8 C1/7 ib
|
|||||||
I(SARrr32 , "sarl", 0, 0) // R32 >>= cl D3/7
|
I(SARrr32 , "sarl", 0, 0) // R32 >>= cl D3/7
|
||||||
I(SARir32 , "sarl", 0, 0) // R32 >>= imm8 C1/7 ib
|
I(SARir32 , "sarl", 0, 0) // R32 >>= imm8 C1/7 ib
|
||||||
|
|
||||||
|
|
||||||
|
// Miscellaneous instructions...
|
||||||
|
I(CBW , "cbw", 0, 0) // AH = signext(AL) 98
|
||||||
|
I(CWD , "cwd", 0, 0) // DX = signext(AX) 99
|
||||||
|
I(CWQ , "cwq", 0, 0) // EDX= signext(EAX) 99
|
||||||
|
|
||||||
// At this point, I is dead, so undefine the macro
|
// At this point, I is dead, so undefine the macro
|
||||||
#undef I
|
#undef I
|
||||||
|
Reference in New Issue
Block a user