From: Chris Lattner Date: Sun, 9 Jan 2005 18:52:44 +0000 (+0000) Subject: Initial implementation of FP->INT and INT->FP casts X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=590d800a12018af782a243cbdd3ac7b31d6d0822;p=oota-llvm.git Initial implementation of FP->INT and INT->FP casts Also, fix zero_extend from bool to i8, which fixes Shootout/objinst. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19414 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/X86/X86ISelPattern.cpp b/lib/Target/X86/X86ISelPattern.cpp index 32bea5f5acd..e2cd2c08c4a 100644 --- a/lib/Target/X86/X86ISelPattern.cpp +++ b/lib/Target/X86/X86ISelPattern.cpp @@ -14,7 +14,9 @@ #include "X86.h" #include "X86InstrBuilder.h" #include "X86RegisterInfo.h" +#include "llvm/Constants.h" // FIXME: REMOVE #include "llvm/Function.h" +#include "llvm/CodeGen/MachineConstantPool.h" // FIXME: REMOVE #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/SelectionDAG.h" @@ -657,9 +659,9 @@ unsigned ISel::SelectExpr(SDOperand N) { SDNode *Node = N.Val; - if (N.getOpcode() == ISD::CopyFromReg) + if (Node->getOpcode() == ISD::CopyFromReg) // Just use the specified register as our input. - return dyn_cast(N)->getReg(); + return dyn_cast(Node)->getReg(); // If there are multiple uses of this expression, memorize the // register it is code generated in, instead of emitting it multiple @@ -747,11 +749,18 @@ unsigned ISel::SelectExpr(SDOperand N) { case ISD::ZERO_EXTEND: { int DestIs16 = N.getValueType() == MVT::i16; int SrcIs16 = N.getOperand(0).getValueType() == MVT::i16; + Tmp1 = SelectExpr(N.getOperand(0)); + + // FIXME: This hack is here for zero extension casts from bool to i8. This + // would not be needed if bools were promoted by Legalize. + if (N.getValueType() == MVT::i8) { + BuildMI(BB, X86::MOV8rr, 1, Result).addReg(Tmp1); + return Result; + } static const unsigned Opc[3] = { X86::MOVZX32rr8, X86::MOVZX32rr16, X86::MOVZX16rr8 }; - Tmp1 = SelectExpr(N.getOperand(0)); BuildMI(BB, Opc[SrcIs16+DestIs16*2], 1, Result).addReg(Tmp1); return Result; } @@ -759,6 +768,10 @@ unsigned ISel::SelectExpr(SDOperand N) { int DestIs16 = N.getValueType() == MVT::i16; int SrcIs16 = N.getOperand(0).getValueType() == MVT::i16; + // FIXME: Legalize should promote bools to i8! + assert(N.getOperand(0).getValueType() != MVT::i1 && + "Sign extend from bool not implemented!"); + static const unsigned Opc[3] = { X86::MOVSX32rr8, X86::MOVSX32rr16, X86::MOVSX16rr8 }; @@ -792,6 +805,7 @@ unsigned ISel::SelectExpr(SDOperand N) { // then reading it back into a register. // Create as stack slot to use. + // FIXME: This should automatically be made by the Legalizer! Tmp1 = TLI.getTargetData().getFloatAlignment(); Tmp2 = BB->getParent()->getFrameInfo()->CreateStackObject(4, Tmp1); @@ -803,6 +817,209 @@ unsigned ISel::SelectExpr(SDOperand N) { addFrameReference(BuildMI(BB, X86::FLD32m, 5, Result), Tmp2); ContainsFPCode = true; return Result; + + case ISD::SINT_TO_FP: + case ISD::UINT_TO_FP: { + // FIXME: Most of this grunt work should be done by legalize! + + // Promote the integer to a type supported by FLD. We do this because there + // are no unsigned FLD instructions, so we must promote an unsigned value to + // a larger signed value, then use FLD on the larger value. + // + MVT::ValueType PromoteType = MVT::Other; + MVT::ValueType SrcTy = N.getOperand(0).getValueType(); + unsigned PromoteOpcode = 0; + unsigned RealDestReg = Result; + switch (SrcTy) { + case MVT::i1: + case MVT::i8: + // We don't have the facilities for directly loading byte sized data from + // memory (even signed). Promote it to 16 bits. + PromoteType = MVT::i16; + PromoteOpcode = Node->getOpcode() == ISD::SINT_TO_FP ? + X86::MOVSX16rr8 : X86::MOVZX16rr8; + break; + case MVT::i16: + if (Node->getOpcode() == ISD::UINT_TO_FP) { + PromoteType = MVT::i32; + PromoteOpcode = X86::MOVZX32rr16; + } + break; + default: + // Don't fild into the real destination. + if (Node->getOpcode() == ISD::UINT_TO_FP) + Result = MakeReg(Node->getValueType(0)); + break; + } + + Tmp1 = SelectExpr(N.getOperand(0)); // Get the operand register + + if (PromoteType != MVT::Other) { + Tmp2 = MakeReg(PromoteType); + BuildMI(BB, PromoteOpcode, 1, Tmp2).addReg(Tmp1); + SrcTy = PromoteType; + Tmp1 = Tmp2; + } + + // Spill the integer to memory and reload it from there. + unsigned Size = MVT::getSizeInBits(SrcTy)/8; + MachineFunction *F = BB->getParent(); + int FrameIdx = F->getFrameInfo()->CreateStackObject(Size, Size); + + switch (SrcTy) { + case MVT::i64: + // FIXME: this won't work for cast [u]long to FP + addFrameReference(BuildMI(BB, X86::MOV32mr, 5), + FrameIdx).addReg(Tmp1); + addFrameReference(BuildMI(BB, X86::MOV32mr, 5), + FrameIdx, 4).addReg(Tmp1+1); + addFrameReference(BuildMI(BB, X86::FILD64m, 5, Result), FrameIdx); + break; + case MVT::i32: + addFrameReference(BuildMI(BB, X86::MOV32mr, 5), + FrameIdx).addReg(Tmp1); + addFrameReference(BuildMI(BB, X86::FILD32m, 5, Result), FrameIdx); + break; + case MVT::i16: + addFrameReference(BuildMI(BB, X86::MOV16mr, 5), + FrameIdx).addReg(Tmp1); + addFrameReference(BuildMI(BB, X86::FILD16m, 5, Result), FrameIdx); + break; + default: break; // No promotion required. + } + + if (Node->getOpcode() == ISD::UINT_TO_FP && SrcTy == MVT::i32) { + // If this is a cast from uint -> double, we need to be careful when if + // the "sign" bit is set. If so, we don't want to make a negative number, + // we want to make a positive number. Emit code to add an offset if the + // sign bit is set. + + // Compute whether the sign bit is set by shifting the reg right 31 bits. + unsigned IsNeg = MakeReg(MVT::i32); + BuildMI(BB, X86::SHR32ri, 2, IsNeg).addReg(Tmp1).addImm(31); + + // Create a CP value that has the offset in one word and 0 in the other. + static ConstantInt *TheOffset = ConstantUInt::get(Type::ULongTy, + 0x4f80000000000000ULL); + unsigned CPI = F->getConstantPool()->getConstantPoolIndex(TheOffset); + BuildMI(BB, X86::FADD32m, 5, RealDestReg).addReg(Result) + .addConstantPoolIndex(CPI).addZImm(4).addReg(IsNeg).addSImm(0); + + } else if (Node->getOpcode() == ISD::UINT_TO_FP && SrcTy == MVT::i64) { + // We need special handling for unsigned 64-bit integer sources. If the + // input number has the "sign bit" set, then we loaded it incorrectly as a + // negative 64-bit number. In this case, add an offset value. + + // Emit a test instruction to see if the dynamic input value was signed. + BuildMI(BB, X86::TEST32rr, 2).addReg(Tmp1+1).addReg(Tmp1+1); + + // If the sign bit is set, get a pointer to an offset, otherwise get a + // pointer to a zero. + MachineConstantPool *CP = F->getConstantPool(); + unsigned Zero = MakeReg(MVT::i32); + Constant *Null = Constant::getNullValue(Type::UIntTy); + addConstantPoolReference(BuildMI(BB, X86::LEA32r, 5, Zero), + CP->getConstantPoolIndex(Null)); + unsigned Offset = MakeReg(MVT::i32); + Constant *OffsetCst = ConstantUInt::get(Type::UIntTy, 0x5f800000); + + addConstantPoolReference(BuildMI(BB, X86::LEA32r, 5, Offset), + CP->getConstantPoolIndex(OffsetCst)); + unsigned Addr = MakeReg(MVT::i32); + BuildMI(BB, X86::CMOVS32rr, 2, Addr).addReg(Zero).addReg(Offset); + + // Load the constant for an add. FIXME: this could make an 'fadd' that + // reads directly from memory, but we don't support these yet. + unsigned ConstReg = MakeReg(MVT::f64); + addDirectMem(BuildMI(BB, X86::FLD32m, 4, ConstReg), Addr); + + BuildMI(BB, X86::FpADD, 2, RealDestReg).addReg(ConstReg).addReg(Result); + } + return RealDestReg; + } + case ISD::FP_TO_SINT: + case ISD::FP_TO_UINT: { + // FIXME: Most of this grunt work should be done by legalize! + Tmp1 = SelectExpr(N.getOperand(0)); // Get the operand register + + // Change the floating point control register to use "round towards zero" + // mode when truncating to an integer value. + // + MachineFunction *F = BB->getParent(); + int CWFrameIdx = F->getFrameInfo()->CreateStackObject(2, 2); + addFrameReference(BuildMI(BB, X86::FNSTCW16m, 4), CWFrameIdx); + + // Load the old value of the high byte of the control word... + unsigned HighPartOfCW = MakeReg(MVT::i8); + addFrameReference(BuildMI(BB, X86::MOV8rm, 4, HighPartOfCW), + CWFrameIdx, 1); + + // Set the high part to be round to zero... + addFrameReference(BuildMI(BB, X86::MOV8mi, 5), + CWFrameIdx, 1).addImm(12); + + // Reload the modified control word now... + addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx); + + // Restore the memory image of control word to original value + addFrameReference(BuildMI(BB, X86::MOV8mr, 5), + CWFrameIdx, 1).addReg(HighPartOfCW); + + // We don't have the facilities for directly storing byte sized data to + // memory. Promote it to 16 bits. We also must promote unsigned values to + // larger classes because we only have signed FP stores. + MVT::ValueType StoreClass = Node->getValueType(0); + if (StoreClass == MVT::i8 || Node->getOpcode() == ISD::FP_TO_UINT) + switch (StoreClass) { + case MVT::i8: StoreClass = MVT::i16; break; + case MVT::i16: StoreClass = MVT::i32; break; + case MVT::i32: StoreClass = MVT::i64; break; + // The following treatment of cLong may not be perfectly right, + // but it survives chains of casts of the form + // double->ulong->double. + case MVT::i64: StoreClass = MVT::i64; break; + default: assert(0 && "Unknown store class!"); + } + + // Spill the integer to memory and reload it from there. + unsigned Size = MVT::getSizeInBits(StoreClass)/8; + int FrameIdx = F->getFrameInfo()->CreateStackObject(Size, Size); + + switch (StoreClass) { + default: assert(0 && "Unknown store class!"); + case MVT::i16: + addFrameReference(BuildMI(BB, X86::FIST16m, 5), FrameIdx).addReg(Tmp1); + break; + case MVT::i32: + addFrameReference(BuildMI(BB, X86::FIST16m, 5), FrameIdx).addReg(Tmp1); + break; + case MVT::i64: + addFrameReference(BuildMI(BB, X86::FIST16m, 5), FrameIdx).addReg(Tmp1); + break; + } + + switch (Node->getValueType(0)) { + default: + assert(0 && "Unknown integer type!"); + case MVT::i64: + // FIXME: this isn't gunna work. + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Result), FrameIdx); + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Result+1), FrameIdx, 4); + case MVT::i32: + addFrameReference(BuildMI(BB, X86::MOV32rm, 4, Result), FrameIdx); + break; + case MVT::i16: + addFrameReference(BuildMI(BB, X86::MOV16rm, 4, Result), FrameIdx); + break; + case MVT::i8: + addFrameReference(BuildMI(BB, X86::MOV8rm, 4, Result), FrameIdx); + break; + } + + // Reload the original control word now. + addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx); + return Result; + } case ISD::ADD: // See if we can codegen this as an LEA to fold operations together. if (N.getValueType() == MVT::i32) {