mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-17 21:29:20 +00:00
Implement a lot of cast functionality (no FP or 64)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4944 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
196cee2dba
commit
d474e9cdce
@ -665,45 +665,73 @@ void ISel::visitPHINode(PHINode &PN) {
|
||||
void
|
||||
ISel::visitCastInst (CastInst &CI)
|
||||
{
|
||||
//> cast larger int to smaller int --> copy least significant byte/word w/ mov?
|
||||
//
|
||||
//I'm not really sure what to do with this. We could insert a pseudo-op
|
||||
//that says take the low X bits of a Y bit register, but for now we can just
|
||||
//force the value into, say, EAX, then rip out AL or AX. The advantage of
|
||||
//the former is that the register allocator could use any register it wants,
|
||||
//but for now this obviously doesn't matter. :)
|
||||
|
||||
const Type *targetType = CI.getType ();
|
||||
Value *operand = CI.getOperand (0);
|
||||
unsigned int operandReg = getReg (operand);
|
||||
const Type *sourceType = operand->getType ();
|
||||
unsigned int destReg = getReg (CI);
|
||||
|
||||
// cast to bool:
|
||||
if (targetType == Type::BoolTy) {
|
||||
// Emit Compare
|
||||
BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0);
|
||||
// Emit Set-if-not-zero
|
||||
BuildMI (BB, X86::SETNEr, 1, destReg);
|
||||
return;
|
||||
}
|
||||
|
||||
// if size of target type == size of source type
|
||||
// Emit Mov reg(target) <- reg(source)
|
||||
|
||||
// if size of target type > size of source type
|
||||
// if both types are integer types
|
||||
// if source type is signed
|
||||
// sbyte to short, ushort: Emit movsx 8->16
|
||||
// sbyte to int, uint: Emit movsx 8->32
|
||||
// short to int, uint: Emit movsx 16->32
|
||||
// else if source type is unsigned
|
||||
// ubyte to short, ushort: Emit movzx 8->16
|
||||
// ubyte to int, uint: Emit movzx 8->32
|
||||
// ushort to int, uint: Emit movzx 16->32
|
||||
// if both types are fp types
|
||||
// float to double: Emit fstp, fld (???)
|
||||
|
||||
//
|
||||
// Currently we handle:
|
||||
//
|
||||
// 1) cast * to bool
|
||||
//
|
||||
// 2) cast {sbyte, ubyte} to {sbyte, ubyte}
|
||||
// cast {short, ushort} to {ushort, short}
|
||||
// cast {int, uint, ptr} to {int, uint, ptr}
|
||||
//
|
||||
// 3) cast {sbyte, ubyte} to {ushort, short}
|
||||
// cast {sbyte, ubyte} to {int, uint, ptr}
|
||||
// cast {short, ushort} to {int, uint, ptr}
|
||||
//
|
||||
// 4) cast {int, uint, ptr} to {short, ushort}
|
||||
// cast {int, uint, ptr} to {sbyte, ubyte}
|
||||
// cast {short, ushort} to {sbyte, ubyte}
|
||||
//
|
||||
// 1) Implement casts to bool by using compare on the operand followed
|
||||
// by set if not zero on the result.
|
||||
if (targetType == Type::BoolTy)
|
||||
{
|
||||
BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0);
|
||||
BuildMI (BB, X86::SETNEr, 1, destReg);
|
||||
return;
|
||||
}
|
||||
// 2) Implement casts between values of the same type class (as determined
|
||||
// by getClass) by using a register-to-register move.
|
||||
unsigned int srcClass = getClass (sourceType);
|
||||
unsigned int targClass = getClass (targetType);
|
||||
static const unsigned regRegMove[] = {
|
||||
X86::MOVrr8, X86::MOVrr16, X86::MOVrr32
|
||||
};
|
||||
if ((srcClass < 3) && (targClass < 3) && (srcClass == targClass))
|
||||
{
|
||||
BuildMI (BB, regRegMove[srcClass], 1, destReg).addReg (operandReg);
|
||||
return;
|
||||
}
|
||||
// 3) Handle cast of SMALLER int to LARGER int using a move with sign
|
||||
// extension or zero extension, depending on whether the source type
|
||||
// was signed.
|
||||
if ((srcClass < 3) && (targClass < 3) && (srcClass < targClass))
|
||||
{
|
||||
static const unsigned ops[] = {
|
||||
X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16,
|
||||
X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16
|
||||
};
|
||||
unsigned srcSigned = sourceType->isSigned ();
|
||||
BuildMI (BB, ops[3 * srcSigned + srcClass + targClass - 1], 1,
|
||||
destReg).addReg (operandReg);
|
||||
return;
|
||||
}
|
||||
// 4) Handle cast of LARGER int to SMALLER int using a move to EAX
|
||||
// followed by a move out of AX or AL.
|
||||
if ((srcClass < 3) && (targClass < 3) && (srcClass > targClass))
|
||||
{
|
||||
static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX };
|
||||
BuildMI (BB, regRegMove[srcClass], 1,
|
||||
AReg[srcClass]).addReg (operandReg);
|
||||
BuildMI (BB, regRegMove[targClass], 1, destReg).addReg (AReg[srcClass]);
|
||||
return;
|
||||
}
|
||||
// Anything we haven't handled already, we can't (yet) handle at all.
|
||||
visitInstruction (CI);
|
||||
}
|
||||
|
||||
|
@ -665,45 +665,73 @@ void ISel::visitPHINode(PHINode &PN) {
|
||||
void
|
||||
ISel::visitCastInst (CastInst &CI)
|
||||
{
|
||||
//> cast larger int to smaller int --> copy least significant byte/word w/ mov?
|
||||
//
|
||||
//I'm not really sure what to do with this. We could insert a pseudo-op
|
||||
//that says take the low X bits of a Y bit register, but for now we can just
|
||||
//force the value into, say, EAX, then rip out AL or AX. The advantage of
|
||||
//the former is that the register allocator could use any register it wants,
|
||||
//but for now this obviously doesn't matter. :)
|
||||
|
||||
const Type *targetType = CI.getType ();
|
||||
Value *operand = CI.getOperand (0);
|
||||
unsigned int operandReg = getReg (operand);
|
||||
const Type *sourceType = operand->getType ();
|
||||
unsigned int destReg = getReg (CI);
|
||||
|
||||
// cast to bool:
|
||||
if (targetType == Type::BoolTy) {
|
||||
// Emit Compare
|
||||
BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0);
|
||||
// Emit Set-if-not-zero
|
||||
BuildMI (BB, X86::SETNEr, 1, destReg);
|
||||
return;
|
||||
}
|
||||
|
||||
// if size of target type == size of source type
|
||||
// Emit Mov reg(target) <- reg(source)
|
||||
|
||||
// if size of target type > size of source type
|
||||
// if both types are integer types
|
||||
// if source type is signed
|
||||
// sbyte to short, ushort: Emit movsx 8->16
|
||||
// sbyte to int, uint: Emit movsx 8->32
|
||||
// short to int, uint: Emit movsx 16->32
|
||||
// else if source type is unsigned
|
||||
// ubyte to short, ushort: Emit movzx 8->16
|
||||
// ubyte to int, uint: Emit movzx 8->32
|
||||
// ushort to int, uint: Emit movzx 16->32
|
||||
// if both types are fp types
|
||||
// float to double: Emit fstp, fld (???)
|
||||
|
||||
//
|
||||
// Currently we handle:
|
||||
//
|
||||
// 1) cast * to bool
|
||||
//
|
||||
// 2) cast {sbyte, ubyte} to {sbyte, ubyte}
|
||||
// cast {short, ushort} to {ushort, short}
|
||||
// cast {int, uint, ptr} to {int, uint, ptr}
|
||||
//
|
||||
// 3) cast {sbyte, ubyte} to {ushort, short}
|
||||
// cast {sbyte, ubyte} to {int, uint, ptr}
|
||||
// cast {short, ushort} to {int, uint, ptr}
|
||||
//
|
||||
// 4) cast {int, uint, ptr} to {short, ushort}
|
||||
// cast {int, uint, ptr} to {sbyte, ubyte}
|
||||
// cast {short, ushort} to {sbyte, ubyte}
|
||||
//
|
||||
// 1) Implement casts to bool by using compare on the operand followed
|
||||
// by set if not zero on the result.
|
||||
if (targetType == Type::BoolTy)
|
||||
{
|
||||
BuildMI (BB, X86::CMPri8, 2).addReg (operandReg).addZImm (0);
|
||||
BuildMI (BB, X86::SETNEr, 1, destReg);
|
||||
return;
|
||||
}
|
||||
// 2) Implement casts between values of the same type class (as determined
|
||||
// by getClass) by using a register-to-register move.
|
||||
unsigned int srcClass = getClass (sourceType);
|
||||
unsigned int targClass = getClass (targetType);
|
||||
static const unsigned regRegMove[] = {
|
||||
X86::MOVrr8, X86::MOVrr16, X86::MOVrr32
|
||||
};
|
||||
if ((srcClass < 3) && (targClass < 3) && (srcClass == targClass))
|
||||
{
|
||||
BuildMI (BB, regRegMove[srcClass], 1, destReg).addReg (operandReg);
|
||||
return;
|
||||
}
|
||||
// 3) Handle cast of SMALLER int to LARGER int using a move with sign
|
||||
// extension or zero extension, depending on whether the source type
|
||||
// was signed.
|
||||
if ((srcClass < 3) && (targClass < 3) && (srcClass < targClass))
|
||||
{
|
||||
static const unsigned ops[] = {
|
||||
X86::MOVSXr16r8, X86::MOVSXr32r8, X86::MOVSXr32r16,
|
||||
X86::MOVZXr16r8, X86::MOVZXr32r8, X86::MOVZXr32r16
|
||||
};
|
||||
unsigned srcSigned = sourceType->isSigned ();
|
||||
BuildMI (BB, ops[3 * srcSigned + srcClass + targClass - 1], 1,
|
||||
destReg).addReg (operandReg);
|
||||
return;
|
||||
}
|
||||
// 4) Handle cast of LARGER int to SMALLER int using a move to EAX
|
||||
// followed by a move out of AX or AL.
|
||||
if ((srcClass < 3) && (targClass < 3) && (srcClass > targClass))
|
||||
{
|
||||
static const unsigned AReg[] = { X86::AL, X86::AX, X86::EAX };
|
||||
BuildMI (BB, regRegMove[srcClass], 1,
|
||||
AReg[srcClass]).addReg (operandReg);
|
||||
BuildMI (BB, regRegMove[targClass], 1, destReg).addReg (AReg[srcClass]);
|
||||
return;
|
||||
}
|
||||
// Anything we haven't handled already, we can't (yet) handle at all.
|
||||
visitInstruction (CI);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user