Support add, sub, mul, div, rem on longs/ulongs (latter 3 by emitting libcalls).

Add a big comment containing my notes on how to do setcc for longs/ulongs.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@18086 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Brian Gaeke 2004-11-21 07:13:16 +00:00
parent b10fc0343f
commit 5f91de2b38
2 changed files with 130 additions and 4 deletions

View File

@ -86,6 +86,10 @@ namespace {
BB = MBBMap[&LLVM_BB];
}
void emitOp64LibraryCall (MachineBasicBlock *MBB,
MachineBasicBlock::iterator IP,
unsigned DestReg, const char *FuncName,
unsigned Op0Reg, unsigned Op1Reg);
void visitBinaryOperator(Instruction &I);
void visitShiftInst (ShiftInst &SI) { visitBinaryOperator (SI); }
void visitSetCondInst(SetCondInst &I);
@ -1091,6 +1095,19 @@ void V8ISel::visitGetElementPtrInst (GetElementPtrInst &I) {
I.op_begin ()+1, I.op_end (), outputReg);
}
void V8ISel::emitOp64LibraryCall (MachineBasicBlock *MBB,
MachineBasicBlock::iterator IP,
unsigned DestReg,
const char *FuncName,
unsigned Op0Reg, unsigned Op1Reg) {
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O0).addReg (V8::G0).addReg (Op0Reg);
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O1).addReg (V8::G0).addReg (Op0Reg+1);
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O2).addReg (V8::G0).addReg (Op1Reg);
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O3).addReg (V8::G0).addReg (Op1Reg+1);
BuildMI (*MBB, IP, V8::CALL, 1).addExternalSymbol (FuncName, true);
BuildMI (*MBB, IP, V8::ORrr, 2, DestReg).addReg (V8::G0).addReg (V8::O0);
BuildMI (*MBB, IP, V8::ORrr, 2, DestReg+1).addReg (V8::G0).addReg (V8::O1);
}
void V8ISel::visitBinaryOperator (Instruction &I) {
unsigned DestReg = getReg (I);
@ -1122,11 +1139,36 @@ void V8ISel::visitBinaryOperator (Instruction &I) {
ResultReg = makeAnotherReg (I.getType ());
if (Class == cLong) {
const char *FuncName;
DEBUG (std::cerr << "Class = cLong\n");
DEBUG (std::cerr << "Op0Reg = " << Op0Reg << ", " << Op0Reg+1 << "\n");
DEBUG (std::cerr << "Op1Reg = " << Op1Reg << ", " << Op1Reg+1 << "\n");
DEBUG (std::cerr << "ResultReg = " << ResultReg << ", " << ResultReg+1 << "\n");
DEBUG (std::cerr << "DestReg = " << DestReg << ", " << DestReg+1 << "\n");
switch (I.getOpcode ()) {
case Instruction::Add:
BuildMI (BB, V8::ADDCCrr, 2, ResultReg+1).addReg (Op0Reg+1)
.addReg (Op1Reg+1);
BuildMI (BB, V8::ADDXrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
return;
case Instruction::Sub:
BuildMI (BB, V8::SUBCCrr, 2, ResultReg+1).addReg (Op0Reg+1)
.addReg (Op1Reg+1);
BuildMI (BB, V8::SUBXrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
return;
case Instruction::Mul:
FuncName = I.getType ()->isSigned () ? "__mul64" : "__umul64";
emitOp64LibraryCall (BB, BB->end (), DestReg, FuncName, Op0Reg, Op1Reg);
return;
case Instruction::Div:
FuncName = I.getType ()->isSigned () ? "__div64" : "__udiv64";
emitOp64LibraryCall (BB, BB->end (), DestReg, FuncName, Op0Reg, Op1Reg);
return;
case Instruction::Rem:
FuncName = I.getType ()->isSigned () ? "__rem64" : "__urem64";
emitOp64LibraryCall (BB, BB->end (), DestReg, FuncName, Op0Reg, Op1Reg);
return;
}
}
// FIXME: support long, ulong.
@ -1204,7 +1246,7 @@ void V8ISel::visitBinaryOperator (Instruction &I) {
// Nothing to do here.
break;
case cLong:
// Only support and, or, xor.
// Only support and, or, xor here - others taken care of above.
if (OpCase < 3 || OpCase > 5) {
visitInstruction (I);
return;
@ -1225,9 +1267,30 @@ void V8ISel::visitSetCondInst(SetCondInst &I) {
const Type *Ty = I.getOperand (0)->getType ();
// Compare the two values.
assert (getClass (Ty) != cLong && "can't setcc on longs yet");
if (getClass (Ty) < cLong) {
BuildMI(BB, V8::SUBCCrr, 2, V8::G0).addReg(Op0Reg).addReg(Op1Reg);
} else if (getClass (Ty) == cLong) {
// Here is one way to open-code each of the setccs for SIGNED longs...
// I haven't checked it yet, but you *should* be able to just switch
// bl/bg/ble/bge with bcs/bgu/bleu/bcc to get the version for
// unsigned longs.
// setlt/setge subcc %left_1, %right_1, %g0
// ^^^^^^^^^^^ subxcc %left_0, %right_0, %g0
// bl/bge (as with ordinary setcc)
// setle/setgt subcc %g0, 1, %g0
// ^^^^^^^^^^^ subxcc %left_1, %right_1, %g0
// subxcc %left_0, %right_0, %g0
// ble/bg (as with ordinary setcc)
// seteq/setne xor %left_1, %right_1, %temp_0
// ^^^^^^^^^^^ xor %left_0, %right_0, %temp_1
// subcc %g0, %temp_1, %g0
// seteq setne
// ^^^^^ ^^^^^
// subx %g0, -1, %temp_2 addx %g0, 0, %temp_2
// subcc %g0, %temp_0, %g0
// subx %g0, -1, %temp_3 addx %g0, 0, %temp_3
// and %temp_2, %temp_3, %result or %temp_2, %temp_3, %result
assert (0 && "can't setcc on longs yet");
} else if (getClass (Ty) == cFloat) {
BuildMI(BB, V8::FCMPS, 2).addReg(Op0Reg).addReg(Op1Reg);
} else if (getClass (Ty) == cDouble) {

View File

@ -86,6 +86,10 @@ namespace {
BB = MBBMap[&LLVM_BB];
}
void emitOp64LibraryCall (MachineBasicBlock *MBB,
MachineBasicBlock::iterator IP,
unsigned DestReg, const char *FuncName,
unsigned Op0Reg, unsigned Op1Reg);
void visitBinaryOperator(Instruction &I);
void visitShiftInst (ShiftInst &SI) { visitBinaryOperator (SI); }
void visitSetCondInst(SetCondInst &I);
@ -1091,6 +1095,19 @@ void V8ISel::visitGetElementPtrInst (GetElementPtrInst &I) {
I.op_begin ()+1, I.op_end (), outputReg);
}
void V8ISel::emitOp64LibraryCall (MachineBasicBlock *MBB,
MachineBasicBlock::iterator IP,
unsigned DestReg,
const char *FuncName,
unsigned Op0Reg, unsigned Op1Reg) {
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O0).addReg (V8::G0).addReg (Op0Reg);
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O1).addReg (V8::G0).addReg (Op0Reg+1);
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O2).addReg (V8::G0).addReg (Op1Reg);
BuildMI (*MBB, IP, V8::ORrr, 2, V8::O3).addReg (V8::G0).addReg (Op1Reg+1);
BuildMI (*MBB, IP, V8::CALL, 1).addExternalSymbol (FuncName, true);
BuildMI (*MBB, IP, V8::ORrr, 2, DestReg).addReg (V8::G0).addReg (V8::O0);
BuildMI (*MBB, IP, V8::ORrr, 2, DestReg+1).addReg (V8::G0).addReg (V8::O1);
}
void V8ISel::visitBinaryOperator (Instruction &I) {
unsigned DestReg = getReg (I);
@ -1122,11 +1139,36 @@ void V8ISel::visitBinaryOperator (Instruction &I) {
ResultReg = makeAnotherReg (I.getType ());
if (Class == cLong) {
const char *FuncName;
DEBUG (std::cerr << "Class = cLong\n");
DEBUG (std::cerr << "Op0Reg = " << Op0Reg << ", " << Op0Reg+1 << "\n");
DEBUG (std::cerr << "Op1Reg = " << Op1Reg << ", " << Op1Reg+1 << "\n");
DEBUG (std::cerr << "ResultReg = " << ResultReg << ", " << ResultReg+1 << "\n");
DEBUG (std::cerr << "DestReg = " << DestReg << ", " << DestReg+1 << "\n");
switch (I.getOpcode ()) {
case Instruction::Add:
BuildMI (BB, V8::ADDCCrr, 2, ResultReg+1).addReg (Op0Reg+1)
.addReg (Op1Reg+1);
BuildMI (BB, V8::ADDXrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
return;
case Instruction::Sub:
BuildMI (BB, V8::SUBCCrr, 2, ResultReg+1).addReg (Op0Reg+1)
.addReg (Op1Reg+1);
BuildMI (BB, V8::SUBXrr, 2, ResultReg).addReg (Op0Reg).addReg (Op1Reg);
return;
case Instruction::Mul:
FuncName = I.getType ()->isSigned () ? "__mul64" : "__umul64";
emitOp64LibraryCall (BB, BB->end (), DestReg, FuncName, Op0Reg, Op1Reg);
return;
case Instruction::Div:
FuncName = I.getType ()->isSigned () ? "__div64" : "__udiv64";
emitOp64LibraryCall (BB, BB->end (), DestReg, FuncName, Op0Reg, Op1Reg);
return;
case Instruction::Rem:
FuncName = I.getType ()->isSigned () ? "__rem64" : "__urem64";
emitOp64LibraryCall (BB, BB->end (), DestReg, FuncName, Op0Reg, Op1Reg);
return;
}
}
// FIXME: support long, ulong.
@ -1204,7 +1246,7 @@ void V8ISel::visitBinaryOperator (Instruction &I) {
// Nothing to do here.
break;
case cLong:
// Only support and, or, xor.
// Only support and, or, xor here - others taken care of above.
if (OpCase < 3 || OpCase > 5) {
visitInstruction (I);
return;
@ -1225,9 +1267,30 @@ void V8ISel::visitSetCondInst(SetCondInst &I) {
const Type *Ty = I.getOperand (0)->getType ();
// Compare the two values.
assert (getClass (Ty) != cLong && "can't setcc on longs yet");
if (getClass (Ty) < cLong) {
BuildMI(BB, V8::SUBCCrr, 2, V8::G0).addReg(Op0Reg).addReg(Op1Reg);
} else if (getClass (Ty) == cLong) {
// Here is one way to open-code each of the setccs for SIGNED longs...
// I haven't checked it yet, but you *should* be able to just switch
// bl/bg/ble/bge with bcs/bgu/bleu/bcc to get the version for
// unsigned longs.
// setlt/setge subcc %left_1, %right_1, %g0
// ^^^^^^^^^^^ subxcc %left_0, %right_0, %g0
// bl/bge (as with ordinary setcc)
// setle/setgt subcc %g0, 1, %g0
// ^^^^^^^^^^^ subxcc %left_1, %right_1, %g0
// subxcc %left_0, %right_0, %g0
// ble/bg (as with ordinary setcc)
// seteq/setne xor %left_1, %right_1, %temp_0
// ^^^^^^^^^^^ xor %left_0, %right_0, %temp_1
// subcc %g0, %temp_1, %g0
// seteq setne
// ^^^^^ ^^^^^
// subx %g0, -1, %temp_2 addx %g0, 0, %temp_2
// subcc %g0, %temp_0, %g0
// subx %g0, -1, %temp_3 addx %g0, 0, %temp_3
// and %temp_2, %temp_3, %result or %temp_2, %temp_3, %result
assert (0 && "can't setcc on longs yet");
} else if (getClass (Ty) == cFloat) {
BuildMI(BB, V8::FCMPS, 2).addReg(Op0Reg).addReg(Op1Reg);
} else if (getClass (Ty) == cDouble) {