mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-26 23:32:58 +00:00
Add instruction selection code and tests for setcc instructions
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4603 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
ed8e6499dd
commit
1749d6359b
@ -8,6 +8,7 @@
|
||||
#include "X86InstrInfo.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/iTerminators.h"
|
||||
#include "llvm/iOperators.h"
|
||||
#include "llvm/iOther.h"
|
||||
#include "llvm/iPHINode.h"
|
||||
#include "llvm/Type.h"
|
||||
@ -77,6 +78,7 @@ namespace {
|
||||
|
||||
// Other operators
|
||||
void visitShiftInst(ShiftInst &I);
|
||||
void visitSetCondInst(SetCondInst &I);
|
||||
void visitPHINode(PHINode &I);
|
||||
|
||||
void visitInstruction(Instruction &I) {
|
||||
@ -160,6 +162,157 @@ void ISel::copyConstantToRegister(Constant *C, unsigned R) {
|
||||
}
|
||||
}
|
||||
|
||||
/// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
|
||||
/// register, then move it to wherever the result should be.
|
||||
/// We handle FP setcc instructions by pushing them, doing a
|
||||
/// compare-and-pop-twice, and then copying the concodes to the main
|
||||
/// processor's concodes (I didn't make this up, it's in the Intel manual)
|
||||
///
|
||||
void
|
||||
ISel::visitSetCondInst (SetCondInst & I)
|
||||
{
|
||||
// The arguments are already supposed to be of the same type.
|
||||
Value *var1 = I.getOperand (0);
|
||||
Value *var2 = I.getOperand (1);
|
||||
unsigned reg1 = getReg (var1);
|
||||
unsigned reg2 = getReg (var2);
|
||||
unsigned resultReg = getReg (I);
|
||||
unsigned comparisonWidth = var1->getType ()->getPrimitiveSize ();
|
||||
unsigned unsignedComparison = var1->getType ()->isUnsigned ();
|
||||
unsigned resultWidth = I.getType ()->getPrimitiveSize ();
|
||||
bool fpComparison = var1->getType ()->isFloatingPoint ();
|
||||
if (fpComparison)
|
||||
{
|
||||
// Push the variables on the stack with fldl opcodes.
|
||||
// FIXME: assuming var1, var2 are in memory, if not, spill to
|
||||
// stack first
|
||||
switch (comparisonWidth)
|
||||
{
|
||||
case 4:
|
||||
BuildMI (BB, X86::FLDr4, 1, X86::NoReg).addReg (reg1);
|
||||
break;
|
||||
case 8:
|
||||
BuildMI (BB, X86::FLDr8, 1, X86::NoReg).addReg (reg1);
|
||||
break;
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
switch (comparisonWidth)
|
||||
{
|
||||
case 4:
|
||||
BuildMI (BB, X86::FLDr4, 1, X86::NoReg).addReg (reg2);
|
||||
break;
|
||||
case 8:
|
||||
BuildMI (BB, X86::FLDr8, 1, X86::NoReg).addReg (reg2);
|
||||
break;
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
// (Non-trapping) compare and pop twice.
|
||||
// FIXME: Result of comparison -> condition codes, not a register.
|
||||
BuildMI (BB, X86::FUCOMPP, 0);
|
||||
// Move fp status word (concodes) to ax.
|
||||
BuildMI (BB, X86::FNSTSWr8, 1, X86::AX);
|
||||
// Load real concodes from ax.
|
||||
// FIXME: Once again, flags are not modeled.
|
||||
BuildMI (BB, X86::SAHF, 0);
|
||||
}
|
||||
else
|
||||
{ // integer comparison
|
||||
// Emit: cmp <var1>, <var2> (do the comparison). We can
|
||||
// compare 8-bit with 8-bit, 16-bit with 16-bit, 32-bit with
|
||||
// 32-bit.
|
||||
// FIXME: Result of comparison -> condition codes, not a register.
|
||||
switch (comparisonWidth)
|
||||
{
|
||||
case 1:
|
||||
BuildMI (BB, X86::CMPrr8, 2,
|
||||
X86::NoReg).addReg (reg1).addReg (reg2);
|
||||
break;
|
||||
case 2:
|
||||
BuildMI (BB, X86::CMPrr16, 2,
|
||||
X86::NoReg).addReg (reg1).addReg (reg2);
|
||||
break;
|
||||
case 4:
|
||||
BuildMI (BB, X86::CMPrr32, 2,
|
||||
X86::NoReg).addReg (reg1).addReg (reg2);
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Emit setOp instruction (extract concode; clobbers ax),
|
||||
// using the following mapping:
|
||||
// LLVM -> X86 signed X86 unsigned
|
||||
// ----- ----- -----
|
||||
// seteq -> sete sete
|
||||
// setne -> setne setne
|
||||
// setlt -> setl setb
|
||||
// setgt -> setg seta
|
||||
// setle -> setle setbe
|
||||
// setge -> setge setae
|
||||
switch (I.getOpcode ())
|
||||
{
|
||||
case Instruction::SetEQ:
|
||||
BuildMI (BB, X86::SETE, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetGE:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETAE, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETGE, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetGT:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETA, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETG, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetLE:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETBE, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETLE, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetLT:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETB, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETL, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetNE:
|
||||
BuildMI (BB, X86::SETNE, 0, X86::AL);
|
||||
break;
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
// Put it in the result using a move.
|
||||
switch (resultWidth)
|
||||
{
|
||||
case 1:
|
||||
BuildMI (BB, X86::MOVrr8, 1, resultReg).addReg (X86::AL);
|
||||
break;
|
||||
// FIXME: What to do about implicit destination registers?
|
||||
// E.g., you don't specify it, but CBW is more like AX = CBW(AL).
|
||||
case 2:
|
||||
BuildMI (BB, X86::CBW, 0, X86::AX);
|
||||
BuildMI (BB, X86::MOVrr16, 1, resultReg).addReg (X86::AX);
|
||||
break;
|
||||
case 4:
|
||||
BuildMI (BB, X86::CWDE, 0, X86::EAX);
|
||||
BuildMI (BB, X86::MOVrr32, 1, resultReg).addReg (X86::EAX);
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 'ret' instruction - Here we are interested in meeting the x86 ABI. As such,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "X86InstrInfo.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/iTerminators.h"
|
||||
#include "llvm/iOperators.h"
|
||||
#include "llvm/iOther.h"
|
||||
#include "llvm/iPHINode.h"
|
||||
#include "llvm/Type.h"
|
||||
@ -77,6 +78,7 @@ namespace {
|
||||
|
||||
// Other operators
|
||||
void visitShiftInst(ShiftInst &I);
|
||||
void visitSetCondInst(SetCondInst &I);
|
||||
void visitPHINode(PHINode &I);
|
||||
|
||||
void visitInstruction(Instruction &I) {
|
||||
@ -160,6 +162,157 @@ void ISel::copyConstantToRegister(Constant *C, unsigned R) {
|
||||
}
|
||||
}
|
||||
|
||||
/// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
|
||||
/// register, then move it to wherever the result should be.
|
||||
/// We handle FP setcc instructions by pushing them, doing a
|
||||
/// compare-and-pop-twice, and then copying the concodes to the main
|
||||
/// processor's concodes (I didn't make this up, it's in the Intel manual)
|
||||
///
|
||||
void
|
||||
ISel::visitSetCondInst (SetCondInst & I)
|
||||
{
|
||||
// The arguments are already supposed to be of the same type.
|
||||
Value *var1 = I.getOperand (0);
|
||||
Value *var2 = I.getOperand (1);
|
||||
unsigned reg1 = getReg (var1);
|
||||
unsigned reg2 = getReg (var2);
|
||||
unsigned resultReg = getReg (I);
|
||||
unsigned comparisonWidth = var1->getType ()->getPrimitiveSize ();
|
||||
unsigned unsignedComparison = var1->getType ()->isUnsigned ();
|
||||
unsigned resultWidth = I.getType ()->getPrimitiveSize ();
|
||||
bool fpComparison = var1->getType ()->isFloatingPoint ();
|
||||
if (fpComparison)
|
||||
{
|
||||
// Push the variables on the stack with fldl opcodes.
|
||||
// FIXME: assuming var1, var2 are in memory, if not, spill to
|
||||
// stack first
|
||||
switch (comparisonWidth)
|
||||
{
|
||||
case 4:
|
||||
BuildMI (BB, X86::FLDr4, 1, X86::NoReg).addReg (reg1);
|
||||
break;
|
||||
case 8:
|
||||
BuildMI (BB, X86::FLDr8, 1, X86::NoReg).addReg (reg1);
|
||||
break;
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
switch (comparisonWidth)
|
||||
{
|
||||
case 4:
|
||||
BuildMI (BB, X86::FLDr4, 1, X86::NoReg).addReg (reg2);
|
||||
break;
|
||||
case 8:
|
||||
BuildMI (BB, X86::FLDr8, 1, X86::NoReg).addReg (reg2);
|
||||
break;
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
// (Non-trapping) compare and pop twice.
|
||||
// FIXME: Result of comparison -> condition codes, not a register.
|
||||
BuildMI (BB, X86::FUCOMPP, 0);
|
||||
// Move fp status word (concodes) to ax.
|
||||
BuildMI (BB, X86::FNSTSWr8, 1, X86::AX);
|
||||
// Load real concodes from ax.
|
||||
// FIXME: Once again, flags are not modeled.
|
||||
BuildMI (BB, X86::SAHF, 0);
|
||||
}
|
||||
else
|
||||
{ // integer comparison
|
||||
// Emit: cmp <var1>, <var2> (do the comparison). We can
|
||||
// compare 8-bit with 8-bit, 16-bit with 16-bit, 32-bit with
|
||||
// 32-bit.
|
||||
// FIXME: Result of comparison -> condition codes, not a register.
|
||||
switch (comparisonWidth)
|
||||
{
|
||||
case 1:
|
||||
BuildMI (BB, X86::CMPrr8, 2,
|
||||
X86::NoReg).addReg (reg1).addReg (reg2);
|
||||
break;
|
||||
case 2:
|
||||
BuildMI (BB, X86::CMPrr16, 2,
|
||||
X86::NoReg).addReg (reg1).addReg (reg2);
|
||||
break;
|
||||
case 4:
|
||||
BuildMI (BB, X86::CMPrr32, 2,
|
||||
X86::NoReg).addReg (reg1).addReg (reg2);
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Emit setOp instruction (extract concode; clobbers ax),
|
||||
// using the following mapping:
|
||||
// LLVM -> X86 signed X86 unsigned
|
||||
// ----- ----- -----
|
||||
// seteq -> sete sete
|
||||
// setne -> setne setne
|
||||
// setlt -> setl setb
|
||||
// setgt -> setg seta
|
||||
// setle -> setle setbe
|
||||
// setge -> setge setae
|
||||
switch (I.getOpcode ())
|
||||
{
|
||||
case Instruction::SetEQ:
|
||||
BuildMI (BB, X86::SETE, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetGE:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETAE, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETGE, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetGT:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETA, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETG, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetLE:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETBE, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETLE, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetLT:
|
||||
if (unsignedComparison)
|
||||
BuildMI (BB, X86::SETB, 0, X86::AL);
|
||||
else
|
||||
BuildMI (BB, X86::SETL, 0, X86::AL);
|
||||
break;
|
||||
case Instruction::SetNE:
|
||||
BuildMI (BB, X86::SETNE, 0, X86::AL);
|
||||
break;
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
// Put it in the result using a move.
|
||||
switch (resultWidth)
|
||||
{
|
||||
case 1:
|
||||
BuildMI (BB, X86::MOVrr8, 1, resultReg).addReg (X86::AL);
|
||||
break;
|
||||
// FIXME: What to do about implicit destination registers?
|
||||
// E.g., you don't specify it, but CBW is more like AX = CBW(AL).
|
||||
case 2:
|
||||
BuildMI (BB, X86::CBW, 0, X86::AX);
|
||||
BuildMI (BB, X86::MOVrr16, 1, resultReg).addReg (X86::AX);
|
||||
break;
|
||||
case 4:
|
||||
BuildMI (BB, X86::CWDE, 0, X86::EAX);
|
||||
BuildMI (BB, X86::MOVrr32, 1, resultReg).addReg (X86::EAX);
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
visitInstruction (I);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 'ret' instruction - Here we are interested in meeting the x86 ABI. As such,
|
||||
|
@ -66,7 +66,6 @@ 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
|
||||
I(ANDrr8 , "andb", 0, 0) // R8 &= R8 20/r
|
||||
I(ANDrr16 , "andw", 0, 0) // R16 &= R16 21/r
|
||||
@ -98,11 +97,39 @@ I(SARir16 , "sarw", 0, 0) // R16 >>= imm8 C1/7 ib
|
||||
I(SARrr32 , "sarl", 0, 0) // R32 >>= cl D3/7
|
||||
I(SARir32 , "sarl", 0, 0) // R32 >>= imm8 C1/7 ib
|
||||
|
||||
// Floating point loads
|
||||
I(FLDr4 , "flds", 0, 0) // push float D9/0
|
||||
I(FLDr8 , "fldl ", 0, 0) // push double DD/0
|
||||
|
||||
// Miscellaneous instructions...
|
||||
// Floating point compares
|
||||
I(FUCOMPP , "fucompp", 0, 0) // compare+pop2x DA E9
|
||||
|
||||
// Floating point flag ops
|
||||
I(FNSTSWr8 , "fnstsw", 0, 0) // AX = fp flags DF E0
|
||||
|
||||
// Condition code ops, incl. set if equal/not equal/...
|
||||
I(SAHF , "sahf", 0, 0) // flags = AH 9E
|
||||
I(SETA , "seta", 0, 0) // R8 = > unsign 0F 97
|
||||
I(SETAE , "setae", 0, 0) // R8 = >=unsign 0F 93
|
||||
I(SETB , "setb", 0, 0) // R8 = < unsign 0F 92
|
||||
I(SETBE , "setbe", 0, 0) // R8 = <=unsign 0F 96
|
||||
I(SETE , "sete", 0, 0) // R8 = == 0F 94
|
||||
I(SETG , "setg", 0, 0) // R8 = > signed 0F 9F
|
||||
I(SETGE , "setge", 0, 0) // R8 = >=signed 0F 9D
|
||||
I(SETL , "setl", 0, 0) // R8 = < signed 0F 9C
|
||||
I(SETLE , "setle", 0, 0) // R8 = <=signed 0F 9E
|
||||
I(SETNE , "setne", 0, 0) // R8 = != 0F 95
|
||||
|
||||
// Integer comparisons
|
||||
I(CMPrr8 , "cmpb", 0, 0) // compare R8,R8 38/r
|
||||
I(CMPrr16 , "cmpw", 0, 0) // compare R16,R16 39/r
|
||||
I(CMPrr32 , "cmpl", 0, 0) // compare R32,R32 39/r
|
||||
|
||||
// Sign extenders
|
||||
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
|
||||
I(CWDE , "cwde", 0, 0) // EAX = extend AX 98
|
||||
|
||||
// At this point, I is dead, so undefine the macro
|
||||
#undef I
|
||||
|
20
test/ExecutionEngine/test-setcond-fp.ll
Normal file
20
test/ExecutionEngine/test-setcond-fp.ll
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
void %main() {
|
||||
%double1 = add double 0.0, 0.0
|
||||
%double2 = add double 0.0, 0.0
|
||||
%float1 = add float 0.0, 0.0
|
||||
%float2 = add float 0.0, 0.0
|
||||
%test49 = seteq float %float1, %float2
|
||||
%test50 = setge float %float1, %float2
|
||||
%test51 = setgt float %float1, %float2
|
||||
%test52 = setle float %float1, %float2
|
||||
%test53 = setlt float %float1, %float2
|
||||
%test54 = setne float %float1, %float2
|
||||
%test55 = seteq double %double1, %double2
|
||||
%test56 = setge double %double1, %double2
|
||||
%test57 = setgt double %double1, %double2
|
||||
%test58 = setle double %double1, %double2
|
||||
%test59 = setlt double %double1, %double2
|
||||
%test60 = setne double %double1, %double2
|
||||
ret void
|
||||
}
|
68
test/ExecutionEngine/test-setcond-int.ll
Normal file
68
test/ExecutionEngine/test-setcond-int.ll
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
void %main() {
|
||||
%int1 = add int 0, 0
|
||||
%int2 = add int 0, 0
|
||||
%long1 = add long 0, 0
|
||||
%long2 = add long 0, 0
|
||||
%sbyte1 = add sbyte 0, 0
|
||||
%sbyte2 = add sbyte 0, 0
|
||||
%short1 = add short 0, 0
|
||||
%short2 = add short 0, 0
|
||||
%ubyte1 = add ubyte 0, 0
|
||||
%ubyte2 = add ubyte 0, 0
|
||||
%uint1 = add uint 0, 0
|
||||
%uint2 = add uint 0, 0
|
||||
%ulong1 = add ulong 0, 0
|
||||
%ulong2 = add ulong 0, 0
|
||||
%ushort1 = add ushort 0, 0
|
||||
%ushort2 = add ushort 0, 0
|
||||
%test1 = seteq ubyte %ubyte1, %ubyte2
|
||||
%test2 = setge ubyte %ubyte1, %ubyte2
|
||||
%test3 = setgt ubyte %ubyte1, %ubyte2
|
||||
%test4 = setle ubyte %ubyte1, %ubyte2
|
||||
%test5 = setlt ubyte %ubyte1, %ubyte2
|
||||
%test6 = setne ubyte %ubyte1, %ubyte2
|
||||
%test7 = seteq ushort %ushort1, %ushort2
|
||||
%test8 = setge ushort %ushort1, %ushort2
|
||||
%test9 = setgt ushort %ushort1, %ushort2
|
||||
%test10 = setle ushort %ushort1, %ushort2
|
||||
%test11 = setlt ushort %ushort1, %ushort2
|
||||
%test12 = setne ushort %ushort1, %ushort2
|
||||
%test13 = seteq uint %uint1, %uint2
|
||||
%test14 = setge uint %uint1, %uint2
|
||||
%test15 = setgt uint %uint1, %uint2
|
||||
%test16 = setle uint %uint1, %uint2
|
||||
%test17 = setlt uint %uint1, %uint2
|
||||
%test18 = setne uint %uint1, %uint2
|
||||
%test19 = seteq ulong %ulong1, %ulong2
|
||||
%test20 = setge ulong %ulong1, %ulong2
|
||||
%test21 = setgt ulong %ulong1, %ulong2
|
||||
%test22 = setle ulong %ulong1, %ulong2
|
||||
%test23 = setlt ulong %ulong1, %ulong2
|
||||
%test24 = setne ulong %ulong1, %ulong2
|
||||
%test25 = seteq sbyte %sbyte1, %sbyte2
|
||||
%test26 = setge sbyte %sbyte1, %sbyte2
|
||||
%test27 = setgt sbyte %sbyte1, %sbyte2
|
||||
%test28 = setle sbyte %sbyte1, %sbyte2
|
||||
%test29 = setlt sbyte %sbyte1, %sbyte2
|
||||
%test30 = setne sbyte %sbyte1, %sbyte2
|
||||
%test31 = seteq short %short1, %short2
|
||||
%test32 = setge short %short1, %short2
|
||||
%test33 = setgt short %short1, %short2
|
||||
%test34 = setle short %short1, %short2
|
||||
%test35 = setlt short %short1, %short2
|
||||
%test36 = setne short %short1, %short2
|
||||
%test37 = seteq int %int1, %int2
|
||||
%test38 = setge int %int1, %int2
|
||||
%test39 = setgt int %int1, %int2
|
||||
%test40 = setle int %int1, %int2
|
||||
%test41 = setlt int %int1, %int2
|
||||
%test42 = setne int %int1, %int2
|
||||
%test43 = seteq long %long1, %long2
|
||||
%test44 = setge long %long1, %long2
|
||||
%test45 = setgt long %long1, %long2
|
||||
%test46 = setle long %long1, %long2
|
||||
%test47 = setlt long %long1, %long2
|
||||
%test48 = setne long %long1, %long2
|
||||
ret void
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user