Add instruction selection code and tests for setcc instructions
authorBrian Gaeke <gaeke@uiuc.edu>
Thu, 7 Nov 2002 17:59:21 +0000 (17:59 +0000)
committerBrian Gaeke <gaeke@uiuc.edu>
Thu, 7 Nov 2002 17:59:21 +0000 (17:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4603 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/InstSelectSimple.cpp
lib/Target/X86/X86ISelSimple.cpp
lib/Target/X86/X86InstrInfo.def
test/ExecutionEngine/test-setcond-fp.ll [new file with mode: 0644]
test/ExecutionEngine/test-setcond-int.ll [new file with mode: 0644]

index 8cbe969843d4300f7b683f06d51264e1d4b47881..af352ae6059ebbc206e83a0acb83cf3d1f5226b4 100644 (file)
@@ -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,
index 8cbe969843d4300f7b683f06d51264e1d4b47881..af352ae6059ebbc206e83a0acb83cf3d1f5226b4 100644 (file)
@@ -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,
index fa242b2d3485a23cb1a4256ed5acadabdf2b96bb..e6c6b073e39fc5e244bb6fd96e5cc2becfe428d9 100644 (file)
@@ -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
 
-
-// Miscellaneous instructions...
+// Floating point loads
+I(FLDr4       , "flds",               0, 0)           // push float    D9/0
+I(FLDr8       , "fldl ",              0, 0)           // push double   DD/0
+
+// 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
diff --git a/test/ExecutionEngine/test-setcond-fp.ll b/test/ExecutionEngine/test-setcond-fp.ll
new file mode 100644 (file)
index 0000000..9191e3f
--- /dev/null
@@ -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
+}
diff --git a/test/ExecutionEngine/test-setcond-int.ll b/test/ExecutionEngine/test-setcond-int.ll
new file mode 100644 (file)
index 0000000..beea516
--- /dev/null
@@ -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
+}