diff options
author | Brian Gaeke <gaeke@uiuc.edu> | 2002-11-07 17:59:21 +0000 |
---|---|---|
committer | Brian Gaeke <gaeke@uiuc.edu> | 2002-11-07 17:59:21 +0000 |
commit | 1749d6359be1e815cfac3295b4145203986fd74b (patch) | |
tree | 1a8e857ad19221e6a5c3ac57ba1fe2e80a5828f5 /lib/Target | |
parent | ed8e6499ddab9d504b35c413377250d481c1946d (diff) |
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
Diffstat (limited to 'lib/Target')
-rw-r--r-- | lib/Target/X86/InstSelectSimple.cpp | 153 | ||||
-rw-r--r-- | lib/Target/X86/X86ISelSimple.cpp | 153 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrInfo.def | 33 |
3 files changed, 336 insertions, 3 deletions
diff --git a/lib/Target/X86/InstSelectSimple.cpp b/lib/Target/X86/InstSelectSimple.cpp index 8cbe969843..af352ae605 100644 --- a/lib/Target/X86/InstSelectSimple.cpp +++ b/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 <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, diff --git a/lib/Target/X86/X86ISelSimple.cpp b/lib/Target/X86/X86ISelSimple.cpp index 8cbe969843..af352ae605 100644 --- a/lib/Target/X86/X86ISelSimple.cpp +++ b/lib/Target/X86/X86ISelSimple.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 <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, diff --git a/lib/Target/X86/X86InstrInfo.def b/lib/Target/X86/X86InstrInfo.def index fa242b2d34..e6c6b073e3 100644 --- a/lib/Target/X86/X86InstrInfo.def +++ b/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 - -// 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 |