diff --git a/llvm/lib/Target/X86/InstSelectSimple.cpp b/llvm/lib/Target/X86/InstSelectSimple.cpp index 8cbe969843d4..af352ae6059e 100644 --- a/llvm/lib/Target/X86/InstSelectSimple.cpp +++ b/llvm/lib/Target/X86/InstSelectSimple.cpp @@ -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 , (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, diff --git a/llvm/lib/Target/X86/X86InstrInfo.def b/llvm/lib/Target/X86/X86InstrInfo.def index fa242b2d3485..e6c6b073e39f 100644 --- a/llvm/lib/Target/X86/X86InstrInfo.def +++ b/llvm/lib/Target/X86/X86InstrInfo.def @@ -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 diff --git a/llvm/test/Regression/Jello/test-setcond-fp.ll b/llvm/test/Regression/Jello/test-setcond-fp.ll new file mode 100644 index 000000000000..9191e3fc09e8 --- /dev/null +++ b/llvm/test/Regression/Jello/test-setcond-fp.ll @@ -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/llvm/test/Regression/Jello/test-setcond-int.ll b/llvm/test/Regression/Jello/test-setcond-int.ll new file mode 100644 index 000000000000..beea516afd01 --- /dev/null +++ b/llvm/test/Regression/Jello/test-setcond-int.ll @@ -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 +}