2006-05-24 07:20:42 +08:00
|
|
|
//===-- X86ISelLowering.cpp - X86 DAG Lowering Implementation -------------===//
|
2005-11-15 08:40:23 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by Chris Lattner and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the interfaces that X86 uses to lower LLVM code into a
|
|
|
|
// selection DAG.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "X86.h"
|
2006-01-17 05:21:29 +08:00
|
|
|
#include "X86InstrBuilder.h"
|
2005-11-15 08:40:23 +08:00
|
|
|
#include "X86ISelLowering.h"
|
2006-06-07 07:30:24 +08:00
|
|
|
#include "X86MachineFunctionInfo.h"
|
2005-11-15 08:40:23 +08:00
|
|
|
#include "X86TargetMachine.h"
|
|
|
|
#include "llvm/CallingConv.h"
|
2006-02-01 06:28:30 +08:00
|
|
|
#include "llvm/Constants.h"
|
2006-04-29 05:29:37 +08:00
|
|
|
#include "llvm/DerivedTypes.h"
|
2005-11-15 08:40:23 +08:00
|
|
|
#include "llvm/Function.h"
|
2006-04-06 07:38:46 +08:00
|
|
|
#include "llvm/Intrinsics.h"
|
2006-03-14 07:18:16 +08:00
|
|
|
#include "llvm/ADT/VectorExtras.h"
|
|
|
|
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
|
2005-11-15 08:40:23 +08:00
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
2006-01-11 08:33:36 +08:00
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2005-11-15 08:40:23 +08:00
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
|
|
|
#include "llvm/CodeGen/SSARegMap.h"
|
2006-01-31 11:14:29 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2005-11-15 08:40:23 +08:00
|
|
|
#include "llvm/Target/TargetOptions.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
// FIXME: temporary.
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
static cl::opt<bool> EnableFastCC("enable-x86-fastcc", cl::Hidden,
|
|
|
|
cl::desc("Enable fastcc on X86"));
|
|
|
|
|
|
|
|
X86TargetLowering::X86TargetLowering(TargetMachine &TM)
|
|
|
|
: TargetLowering(TM) {
|
2006-01-27 16:10:46 +08:00
|
|
|
Subtarget = &TM.getSubtarget<X86Subtarget>();
|
|
|
|
X86ScalarSSE = Subtarget->hasSSE2();
|
2006-09-08 14:48:29 +08:00
|
|
|
X86StackPtr = Subtarget->is64Bit() ? X86::RSP : X86::ESP;
|
2006-01-27 16:10:46 +08:00
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
// Set up the TargetLowering object.
|
|
|
|
|
|
|
|
// X86 is weird, it always uses i8 for shift amounts and setcc results.
|
|
|
|
setShiftAmountType(MVT::i8);
|
|
|
|
setSetCCResultType(MVT::i8);
|
|
|
|
setSetCCResultContents(ZeroOrOneSetCCResult);
|
2006-01-25 17:15:17 +08:00
|
|
|
setSchedulingPreference(SchedulingForRegPressure);
|
2005-11-15 08:40:23 +08:00
|
|
|
setShiftAmountFlavor(Mask); // shl X, 32 == shl X, 0
|
2006-09-08 14:48:29 +08:00
|
|
|
setStackPointerRegisterToSaveRestore(X86StackPtr);
|
2006-03-17 05:47:42 +08:00
|
|
|
|
2006-03-23 03:22:18 +08:00
|
|
|
if (!Subtarget->isTargetDarwin())
|
2006-03-18 04:31:41 +08:00
|
|
|
// Darwin should use _setjmp/_longjmp instead of setjmp/longjmp.
|
|
|
|
setUseUnderscoreSetJmpLongJmp(true);
|
|
|
|
|
2006-03-17 05:47:42 +08:00
|
|
|
// Add legal addressing mode scale values.
|
|
|
|
addLegalAddressScale(8);
|
|
|
|
addLegalAddressScale(4);
|
|
|
|
addLegalAddressScale(2);
|
|
|
|
// Enter the ones which require both scale + index last. These are more
|
|
|
|
// expensive.
|
|
|
|
addLegalAddressScale(9);
|
|
|
|
addLegalAddressScale(5);
|
|
|
|
addLegalAddressScale(3);
|
2006-01-29 14:26:08 +08:00
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
// Set up the register classes.
|
2006-05-16 15:21:53 +08:00
|
|
|
addRegisterClass(MVT::i8, X86::GR8RegisterClass);
|
|
|
|
addRegisterClass(MVT::i16, X86::GR16RegisterClass);
|
|
|
|
addRegisterClass(MVT::i32, X86::GR32RegisterClass);
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
addRegisterClass(MVT::i64, X86::GR64RegisterClass);
|
2005-11-15 08:40:23 +08:00
|
|
|
|
|
|
|
// Promote all UINT_TO_FP to larger SINT_TO_FP's, as X86 doesn't have this
|
|
|
|
// operation.
|
|
|
|
setOperationAction(ISD::UINT_TO_FP , MVT::i1 , Promote);
|
|
|
|
setOperationAction(ISD::UINT_TO_FP , MVT::i8 , Promote);
|
|
|
|
setOperationAction(ISD::UINT_TO_FP , MVT::i16 , Promote);
|
2006-01-17 10:32:49 +08:00
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit()) {
|
|
|
|
setOperationAction(ISD::UINT_TO_FP , MVT::i64 , Expand);
|
2006-01-17 10:32:49 +08:00
|
|
|
setOperationAction(ISD::UINT_TO_FP , MVT::i32 , Promote);
|
2006-09-08 14:48:29 +08:00
|
|
|
} else {
|
|
|
|
if (X86ScalarSSE)
|
|
|
|
// If SSE i64 SINT_TO_FP is not available, expand i32 UINT_TO_FP.
|
|
|
|
setOperationAction(ISD::UINT_TO_FP , MVT::i32 , Expand);
|
|
|
|
else
|
|
|
|
setOperationAction(ISD::UINT_TO_FP , MVT::i32 , Promote);
|
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
|
|
|
|
// Promote i1/i8 SINT_TO_FP to larger SINT_TO_FP's, as X86 doesn't have
|
|
|
|
// this operation.
|
|
|
|
setOperationAction(ISD::SINT_TO_FP , MVT::i1 , Promote);
|
|
|
|
setOperationAction(ISD::SINT_TO_FP , MVT::i8 , Promote);
|
2006-02-17 08:03:04 +08:00
|
|
|
// SSE has no i16 to fp conversion, only i32
|
2006-01-31 06:13:22 +08:00
|
|
|
if (X86ScalarSSE)
|
|
|
|
setOperationAction(ISD::SINT_TO_FP , MVT::i16 , Promote);
|
2006-02-17 15:01:52 +08:00
|
|
|
else {
|
|
|
|
setOperationAction(ISD::SINT_TO_FP , MVT::i16 , Custom);
|
|
|
|
setOperationAction(ISD::SINT_TO_FP , MVT::i32 , Custom);
|
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
if (!Subtarget->is64Bit()) {
|
|
|
|
// Custom lower SINT_TO_FP and FP_TO_SINT from/to i64 in 32-bit mode.
|
|
|
|
setOperationAction(ISD::SINT_TO_FP , MVT::i64 , Custom);
|
|
|
|
setOperationAction(ISD::FP_TO_SINT , MVT::i64 , Custom);
|
|
|
|
}
|
2006-01-30 16:02:57 +08:00
|
|
|
|
2006-01-31 06:13:22 +08:00
|
|
|
// Promote i1/i8 FP_TO_SINT to larger FP_TO_SINTS's, as X86 doesn't have
|
|
|
|
// this operation.
|
|
|
|
setOperationAction(ISD::FP_TO_SINT , MVT::i1 , Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_SINT , MVT::i8 , Promote);
|
|
|
|
|
|
|
|
if (X86ScalarSSE) {
|
|
|
|
setOperationAction(ISD::FP_TO_SINT , MVT::i16 , Promote);
|
|
|
|
} else {
|
2005-11-15 08:40:23 +08:00
|
|
|
setOperationAction(ISD::FP_TO_SINT , MVT::i16 , Custom);
|
2006-01-31 06:13:22 +08:00
|
|
|
setOperationAction(ISD::FP_TO_SINT , MVT::i32 , Custom);
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Handle FP_TO_UINT by promoting the destination to a larger signed
|
|
|
|
// conversion.
|
|
|
|
setOperationAction(ISD::FP_TO_UINT , MVT::i1 , Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_UINT , MVT::i8 , Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_UINT , MVT::i16 , Promote);
|
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit()) {
|
|
|
|
setOperationAction(ISD::FP_TO_UINT , MVT::i64 , Expand);
|
2005-11-15 08:40:23 +08:00
|
|
|
setOperationAction(ISD::FP_TO_UINT , MVT::i32 , Promote);
|
2006-09-08 14:48:29 +08:00
|
|
|
} else {
|
|
|
|
if (X86ScalarSSE && !Subtarget->hasSSE3())
|
|
|
|
// Expand FP_TO_UINT into a select.
|
|
|
|
// FIXME: We would like to use a Custom expander here eventually to do
|
|
|
|
// the optimal thing for SSE vs. the default expansion in the legalizer.
|
|
|
|
setOperationAction(ISD::FP_TO_UINT , MVT::i32 , Expand);
|
|
|
|
else
|
|
|
|
// With SSE3 we can use fisttpll to convert to a signed i64.
|
|
|
|
setOperationAction(ISD::FP_TO_UINT , MVT::i32 , Promote);
|
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-01-31 06:13:22 +08:00
|
|
|
setOperationAction(ISD::BIT_CONVERT , MVT::f32 , Expand);
|
|
|
|
setOperationAction(ISD::BIT_CONVERT , MVT::i32 , Expand);
|
2005-12-23 13:15:23 +08:00
|
|
|
|
2006-02-17 15:01:52 +08:00
|
|
|
setOperationAction(ISD::BRCOND , MVT::Other, Custom);
|
2006-02-01 15:19:44 +08:00
|
|
|
setOperationAction(ISD::BR_CC , MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::SELECT_CC , MVT::Other, Expand);
|
2005-11-15 08:40:23 +08:00
|
|
|
setOperationAction(ISD::MEMMOVE , MVT::Other, Expand);
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Expand);
|
2005-11-15 08:40:23 +08:00
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16 , Expand);
|
2005-12-08 01:59:14 +08:00
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
|
2005-11-15 08:40:23 +08:00
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
|
|
|
|
setOperationAction(ISD::FP_ROUND_INREG , MVT::f32 , Expand);
|
|
|
|
setOperationAction(ISD::SEXTLOAD , MVT::i1 , Expand);
|
|
|
|
setOperationAction(ISD::FREM , MVT::f64 , Expand);
|
2006-09-08 14:48:29 +08:00
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
setOperationAction(ISD::CTPOP , MVT::i8 , Expand);
|
|
|
|
setOperationAction(ISD::CTTZ , MVT::i8 , Expand);
|
|
|
|
setOperationAction(ISD::CTLZ , MVT::i8 , Expand);
|
|
|
|
setOperationAction(ISD::CTPOP , MVT::i16 , Expand);
|
|
|
|
setOperationAction(ISD::CTTZ , MVT::i16 , Expand);
|
|
|
|
setOperationAction(ISD::CTLZ , MVT::i16 , Expand);
|
|
|
|
setOperationAction(ISD::CTPOP , MVT::i32 , Expand);
|
|
|
|
setOperationAction(ISD::CTTZ , MVT::i32 , Expand);
|
|
|
|
setOperationAction(ISD::CTLZ , MVT::i32 , Expand);
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit()) {
|
|
|
|
setOperationAction(ISD::CTPOP , MVT::i64 , Expand);
|
|
|
|
setOperationAction(ISD::CTTZ , MVT::i64 , Expand);
|
|
|
|
setOperationAction(ISD::CTLZ , MVT::i64 , Expand);
|
|
|
|
}
|
|
|
|
|
2005-11-21 05:41:10 +08:00
|
|
|
setOperationAction(ISD::READCYCLECOUNTER , MVT::i64 , Custom);
|
2006-01-14 11:14:10 +08:00
|
|
|
setOperationAction(ISD::BSWAP , MVT::i16 , Expand);
|
2006-01-12 05:21:00 +08:00
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
// These should be promoted to a larger select which is supported.
|
|
|
|
setOperationAction(ISD::SELECT , MVT::i1 , Promote);
|
|
|
|
setOperationAction(ISD::SELECT , MVT::i8 , Promote);
|
2006-02-17 08:03:04 +08:00
|
|
|
// X86 wants to expand cmov itself.
|
2006-02-17 15:01:52 +08:00
|
|
|
setOperationAction(ISD::SELECT , MVT::i16 , Custom);
|
|
|
|
setOperationAction(ISD::SELECT , MVT::i32 , Custom);
|
|
|
|
setOperationAction(ISD::SELECT , MVT::f32 , Custom);
|
|
|
|
setOperationAction(ISD::SELECT , MVT::f64 , Custom);
|
|
|
|
setOperationAction(ISD::SETCC , MVT::i8 , Custom);
|
|
|
|
setOperationAction(ISD::SETCC , MVT::i16 , Custom);
|
|
|
|
setOperationAction(ISD::SETCC , MVT::i32 , Custom);
|
|
|
|
setOperationAction(ISD::SETCC , MVT::f32 , Custom);
|
|
|
|
setOperationAction(ISD::SETCC , MVT::f64 , Custom);
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit()) {
|
|
|
|
setOperationAction(ISD::SELECT , MVT::i64 , Custom);
|
|
|
|
setOperationAction(ISD::SETCC , MVT::i64 , Custom);
|
|
|
|
}
|
2006-02-17 08:03:04 +08:00
|
|
|
// X86 ret instruction may pop stack.
|
2006-02-17 15:01:52 +08:00
|
|
|
setOperationAction(ISD::RET , MVT::Other, Custom);
|
2006-02-17 08:03:04 +08:00
|
|
|
// Darwin ABI issue.
|
2006-02-18 08:15:05 +08:00
|
|
|
setOperationAction(ISD::ConstantPool , MVT::i32 , Custom);
|
2006-04-23 02:53:45 +08:00
|
|
|
setOperationAction(ISD::JumpTable , MVT::i32 , Custom);
|
2006-02-17 15:01:52 +08:00
|
|
|
setOperationAction(ISD::GlobalAddress , MVT::i32 , Custom);
|
2006-02-24 04:41:18 +08:00
|
|
|
setOperationAction(ISD::ExternalSymbol , MVT::i32 , Custom);
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit()) {
|
|
|
|
setOperationAction(ISD::ConstantPool , MVT::i64 , Custom);
|
|
|
|
setOperationAction(ISD::JumpTable , MVT::i64 , Custom);
|
|
|
|
setOperationAction(ISD::GlobalAddress , MVT::i64 , Custom);
|
|
|
|
setOperationAction(ISD::ExternalSymbol, MVT::i64 , Custom);
|
|
|
|
}
|
2006-02-17 08:03:04 +08:00
|
|
|
// 64-bit addm sub, shl, sra, srl (iff 32-bit x86)
|
2006-02-17 15:01:52 +08:00
|
|
|
setOperationAction(ISD::SHL_PARTS , MVT::i32 , Custom);
|
|
|
|
setOperationAction(ISD::SRA_PARTS , MVT::i32 , Custom);
|
|
|
|
setOperationAction(ISD::SRL_PARTS , MVT::i32 , Custom);
|
2006-02-17 08:03:04 +08:00
|
|
|
// X86 wants to expand memset / memcpy itself.
|
2006-02-17 15:01:52 +08:00
|
|
|
setOperationAction(ISD::MEMSET , MVT::Other, Custom);
|
|
|
|
setOperationAction(ISD::MEMCPY , MVT::Other, Custom);
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2005-11-29 14:16:21 +08:00
|
|
|
// We don't have line number support yet.
|
|
|
|
setOperationAction(ISD::LOCATION, MVT::Other, Expand);
|
2006-01-05 09:47:43 +08:00
|
|
|
setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
|
2006-03-07 10:02:57 +08:00
|
|
|
// FIXME - use subtarget debug flags
|
2006-03-23 03:22:18 +08:00
|
|
|
if (!Subtarget->isTargetDarwin())
|
2006-03-07 10:02:57 +08:00
|
|
|
setOperationAction(ISD::DEBUG_LABEL, MVT::Other, Expand);
|
2005-11-29 14:16:21 +08:00
|
|
|
|
2006-01-26 02:21:52 +08:00
|
|
|
// VASTART needs to be custom lowered to use the VarArgsFrameIndex
|
|
|
|
setOperationAction(ISD::VASTART , MVT::Other, Custom);
|
|
|
|
|
|
|
|
// Use the default implementation.
|
|
|
|
setOperationAction(ISD::VAARG , MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VACOPY , MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VAEND , MVT::Other, Expand);
|
2006-01-15 17:00:21 +08:00
|
|
|
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand);
|
2006-01-15 17:00:21 +08:00
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Expand);
|
2006-01-13 10:42:53 +08:00
|
|
|
|
2006-03-05 13:08:37 +08:00
|
|
|
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
|
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
if (X86ScalarSSE) {
|
|
|
|
// Set up the FP register classes.
|
2006-01-12 16:27:59 +08:00
|
|
|
addRegisterClass(MVT::f32, X86::FR32RegisterClass);
|
|
|
|
addRegisterClass(MVT::f64, X86::FR64RegisterClass);
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-02-01 06:28:30 +08:00
|
|
|
// Use ANDPD to simulate FABS.
|
|
|
|
setOperationAction(ISD::FABS , MVT::f64, Custom);
|
|
|
|
setOperationAction(ISD::FABS , MVT::f32, Custom);
|
|
|
|
|
|
|
|
// Use XORP to simulate FNEG.
|
|
|
|
setOperationAction(ISD::FNEG , MVT::f64, Custom);
|
|
|
|
setOperationAction(ISD::FNEG , MVT::f32, Custom);
|
|
|
|
|
2006-02-02 08:28:23 +08:00
|
|
|
// We don't support sin/cos/fmod
|
2005-11-15 08:40:23 +08:00
|
|
|
setOperationAction(ISD::FSIN , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FREM , MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FSIN , MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f32, Expand);
|
|
|
|
setOperationAction(ISD::FREM , MVT::f32, Expand);
|
|
|
|
|
2006-01-29 14:26:08 +08:00
|
|
|
// Expand FP immediates into loads from the stack, except for the special
|
|
|
|
// cases we handle.
|
|
|
|
setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::ConstantFP, MVT::f32, Expand);
|
2005-11-15 08:40:23 +08:00
|
|
|
addLegalFPImmediate(+0.0); // xorps / xorpd
|
|
|
|
} else {
|
|
|
|
// Set up the FP register classes.
|
|
|
|
addRegisterClass(MVT::f64, X86::RFPRegisterClass);
|
2006-01-29 14:44:22 +08:00
|
|
|
|
|
|
|
setOperationAction(ISD::UNDEF, MVT::f64, Expand);
|
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
if (!UnsafeFPMath) {
|
|
|
|
setOperationAction(ISD::FSIN , MVT::f64 , Expand);
|
|
|
|
setOperationAction(ISD::FCOS , MVT::f64 , Expand);
|
|
|
|
}
|
|
|
|
|
2006-01-29 14:26:08 +08:00
|
|
|
setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
|
2005-11-15 08:40:23 +08:00
|
|
|
addLegalFPImmediate(+0.0); // FLD0
|
|
|
|
addLegalFPImmediate(+1.0); // FLD1
|
|
|
|
addLegalFPImmediate(-0.0); // FLD0/FCHS
|
|
|
|
addLegalFPImmediate(-1.0); // FLD1/FCHS
|
|
|
|
}
|
2006-02-22 10:26:30 +08:00
|
|
|
|
2006-03-01 09:11:20 +08:00
|
|
|
// First set operation action for all vector types to expand. Then we
|
|
|
|
// will selectively turn on ones that can be effectively codegen'd.
|
|
|
|
for (unsigned VT = (unsigned)MVT::Vector + 1;
|
|
|
|
VT != (unsigned)MVT::LAST_VALUETYPE; VT++) {
|
|
|
|
setOperationAction(ISD::ADD , (MVT::ValueType)VT, Expand);
|
|
|
|
setOperationAction(ISD::SUB , (MVT::ValueType)VT, Expand);
|
|
|
|
setOperationAction(ISD::MUL , (MVT::ValueType)VT, Expand);
|
|
|
|
setOperationAction(ISD::LOAD, (MVT::ValueType)VT, Expand);
|
2006-04-01 03:22:53 +08:00
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, (MVT::ValueType)VT, Expand);
|
2006-03-22 04:51:05 +08:00
|
|
|
setOperationAction(ISD::EXTRACT_VECTOR_ELT, (MVT::ValueType)VT, Expand);
|
2006-04-01 03:22:53 +08:00
|
|
|
setOperationAction(ISD::INSERT_VECTOR_ELT, (MVT::ValueType)VT, Expand);
|
2006-03-01 09:11:20 +08:00
|
|
|
}
|
|
|
|
|
2006-03-23 03:22:18 +08:00
|
|
|
if (Subtarget->hasMMX()) {
|
2006-02-22 10:26:30 +08:00
|
|
|
addRegisterClass(MVT::v8i8, X86::VR64RegisterClass);
|
|
|
|
addRegisterClass(MVT::v4i16, X86::VR64RegisterClass);
|
|
|
|
addRegisterClass(MVT::v2i32, X86::VR64RegisterClass);
|
|
|
|
|
2006-03-01 09:11:20 +08:00
|
|
|
// FIXME: add MMX packed arithmetics
|
2006-03-22 07:01:21 +08:00
|
|
|
setOperationAction(ISD::BUILD_VECTOR, MVT::v8i8, Expand);
|
|
|
|
setOperationAction(ISD::BUILD_VECTOR, MVT::v4i16, Expand);
|
|
|
|
setOperationAction(ISD::BUILD_VECTOR, MVT::v2i32, Expand);
|
2006-02-22 10:26:30 +08:00
|
|
|
}
|
|
|
|
|
2006-03-23 03:22:18 +08:00
|
|
|
if (Subtarget->hasSSE1()) {
|
2006-02-22 10:26:30 +08:00
|
|
|
addRegisterClass(MVT::v4f32, X86::VR128RegisterClass);
|
|
|
|
|
2006-04-13 05:21:57 +08:00
|
|
|
setOperationAction(ISD::AND, MVT::v4f32, Legal);
|
|
|
|
setOperationAction(ISD::OR, MVT::v4f32, Legal);
|
|
|
|
setOperationAction(ISD::XOR, MVT::v4f32, Legal);
|
2006-04-10 15:23:14 +08:00
|
|
|
setOperationAction(ISD::ADD, MVT::v4f32, Legal);
|
|
|
|
setOperationAction(ISD::SUB, MVT::v4f32, Legal);
|
|
|
|
setOperationAction(ISD::MUL, MVT::v4f32, Legal);
|
|
|
|
setOperationAction(ISD::LOAD, MVT::v4f32, Legal);
|
|
|
|
setOperationAction(ISD::BUILD_VECTOR, MVT::v4f32, Custom);
|
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4f32, Custom);
|
2006-04-04 04:53:28 +08:00
|
|
|
setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v4f32, Custom);
|
2006-04-10 15:23:14 +08:00
|
|
|
setOperationAction(ISD::SELECT, MVT::v4f32, Custom);
|
2006-02-22 10:26:30 +08:00
|
|
|
}
|
|
|
|
|
2006-03-23 03:22:18 +08:00
|
|
|
if (Subtarget->hasSSE2()) {
|
2006-02-22 10:26:30 +08:00
|
|
|
addRegisterClass(MVT::v2f64, X86::VR128RegisterClass);
|
|
|
|
addRegisterClass(MVT::v16i8, X86::VR128RegisterClass);
|
|
|
|
addRegisterClass(MVT::v8i16, X86::VR128RegisterClass);
|
|
|
|
addRegisterClass(MVT::v4i32, X86::VR128RegisterClass);
|
|
|
|
addRegisterClass(MVT::v2i64, X86::VR128RegisterClass);
|
|
|
|
|
2006-04-10 15:23:14 +08:00
|
|
|
setOperationAction(ISD::ADD, MVT::v2f64, Legal);
|
|
|
|
setOperationAction(ISD::ADD, MVT::v16i8, Legal);
|
|
|
|
setOperationAction(ISD::ADD, MVT::v8i16, Legal);
|
|
|
|
setOperationAction(ISD::ADD, MVT::v4i32, Legal);
|
|
|
|
setOperationAction(ISD::SUB, MVT::v2f64, Legal);
|
|
|
|
setOperationAction(ISD::SUB, MVT::v16i8, Legal);
|
|
|
|
setOperationAction(ISD::SUB, MVT::v8i16, Legal);
|
|
|
|
setOperationAction(ISD::SUB, MVT::v4i32, Legal);
|
2006-04-13 13:10:25 +08:00
|
|
|
setOperationAction(ISD::MUL, MVT::v8i16, Legal);
|
2006-04-10 15:23:14 +08:00
|
|
|
setOperationAction(ISD::MUL, MVT::v2f64, Legal);
|
2006-04-13 05:21:57 +08:00
|
|
|
|
2006-04-10 15:23:14 +08:00
|
|
|
setOperationAction(ISD::SCALAR_TO_VECTOR, MVT::v16i8, Custom);
|
|
|
|
setOperationAction(ISD::SCALAR_TO_VECTOR, MVT::v8i16, Custom);
|
2006-04-13 05:21:57 +08:00
|
|
|
setOperationAction(ISD::INSERT_VECTOR_ELT, MVT::v8i16, Custom);
|
2006-04-18 06:04:06 +08:00
|
|
|
setOperationAction(ISD::INSERT_VECTOR_ELT, MVT::v4i32, Custom);
|
|
|
|
// Implement v4f32 insert_vector_elt in terms of SSE2 v8i16 ones.
|
|
|
|
setOperationAction(ISD::INSERT_VECTOR_ELT, MVT::v4f32, Custom);
|
2006-04-13 05:21:57 +08:00
|
|
|
|
|
|
|
// Custom lower build_vector, vector_shuffle, and extract_vector_elt.
|
|
|
|
for (unsigned VT = (unsigned)MVT::v16i8; VT != (unsigned)MVT::v2i64; VT++) {
|
|
|
|
setOperationAction(ISD::BUILD_VECTOR, (MVT::ValueType)VT, Custom);
|
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, (MVT::ValueType)VT, Custom);
|
|
|
|
setOperationAction(ISD::EXTRACT_VECTOR_ELT, (MVT::ValueType)VT, Custom);
|
|
|
|
}
|
2006-04-10 15:23:14 +08:00
|
|
|
setOperationAction(ISD::BUILD_VECTOR, MVT::v2f64, Custom);
|
|
|
|
setOperationAction(ISD::BUILD_VECTOR, MVT::v2i64, Custom);
|
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2f64, Custom);
|
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v2i64, Custom);
|
2006-04-04 04:53:28 +08:00
|
|
|
setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v2f64, Custom);
|
2006-04-13 05:21:57 +08:00
|
|
|
setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v2i64, Custom);
|
|
|
|
|
|
|
|
// Promote v16i8, v8i16, v4i32 load, select, and, or, xor to v2i64.
|
|
|
|
for (unsigned VT = (unsigned)MVT::v16i8; VT != (unsigned)MVT::v2i64; VT++) {
|
|
|
|
setOperationAction(ISD::AND, (MVT::ValueType)VT, Promote);
|
|
|
|
AddPromotedToType (ISD::AND, (MVT::ValueType)VT, MVT::v2i64);
|
|
|
|
setOperationAction(ISD::OR, (MVT::ValueType)VT, Promote);
|
|
|
|
AddPromotedToType (ISD::OR, (MVT::ValueType)VT, MVT::v2i64);
|
|
|
|
setOperationAction(ISD::XOR, (MVT::ValueType)VT, Promote);
|
|
|
|
AddPromotedToType (ISD::XOR, (MVT::ValueType)VT, MVT::v2i64);
|
2006-04-13 01:12:36 +08:00
|
|
|
setOperationAction(ISD::LOAD, (MVT::ValueType)VT, Promote);
|
|
|
|
AddPromotedToType (ISD::LOAD, (MVT::ValueType)VT, MVT::v2i64);
|
2006-04-13 05:21:57 +08:00
|
|
|
setOperationAction(ISD::SELECT, (MVT::ValueType)VT, Promote);
|
|
|
|
AddPromotedToType (ISD::SELECT, (MVT::ValueType)VT, MVT::v2i64);
|
2006-04-10 15:23:14 +08:00
|
|
|
}
|
2006-04-13 05:21:57 +08:00
|
|
|
|
|
|
|
// Custom lower v2i64 and v2f64 selects.
|
|
|
|
setOperationAction(ISD::LOAD, MVT::v2f64, Legal);
|
2006-04-13 01:12:36 +08:00
|
|
|
setOperationAction(ISD::LOAD, MVT::v2i64, Legal);
|
2006-04-10 15:23:14 +08:00
|
|
|
setOperationAction(ISD::SELECT, MVT::v2f64, Custom);
|
2006-04-13 05:21:57 +08:00
|
|
|
setOperationAction(ISD::SELECT, MVT::v2i64, Custom);
|
2006-02-22 10:26:30 +08:00
|
|
|
}
|
|
|
|
|
2006-04-06 07:38:46 +08:00
|
|
|
// We want to custom lower some of our intrinsics.
|
|
|
|
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
|
|
|
|
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
// We have target-specific dag combine patterns for the following nodes:
|
|
|
|
setTargetDAGCombine(ISD::VECTOR_SHUFFLE);
|
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
computeRegisterProperties();
|
|
|
|
|
2006-02-14 16:25:08 +08:00
|
|
|
// FIXME: These should be based on subtarget info. Plus, the values should
|
|
|
|
// be smaller when we are in optimizing for size mode.
|
2006-02-14 16:38:30 +08:00
|
|
|
maxStoresPerMemset = 16; // For %llvm.memset -> sequence of stores
|
|
|
|
maxStoresPerMemcpy = 16; // For %llvm.memcpy -> sequence of stores
|
|
|
|
maxStoresPerMemmove = 16; // For %llvm.memmove -> sequence of stores
|
2005-11-15 08:40:23 +08:00
|
|
|
allowUnalignedMemoryAccesses = true; // x86 supports it!
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C Calling Convention implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-04-27 13:35:28 +08:00
|
|
|
/// AddLiveIn - This helper function adds the specified physical register to the
|
|
|
|
/// MachineFunction as a live in value. It also creates a corresponding virtual
|
|
|
|
/// register for it.
|
|
|
|
static unsigned AddLiveIn(MachineFunction &MF, unsigned PReg,
|
|
|
|
TargetRegisterClass *RC) {
|
|
|
|
assert(RC->contains(PReg) && "Not the correct regclass!");
|
|
|
|
unsigned VReg = MF.getSSARegMap()->createVirtualRegister(RC);
|
|
|
|
MF.addLiveIn(PReg, VReg);
|
|
|
|
return VReg;
|
|
|
|
}
|
|
|
|
|
2006-04-27 16:31:10 +08:00
|
|
|
/// HowToPassCCCArgument - Returns how an formal argument of the specified type
|
|
|
|
/// should be passed. If it is through stack, returns the size of the stack
|
2006-05-27 02:25:43 +08:00
|
|
|
/// slot; if it is through XMM register, returns the number of XMM registers
|
2006-04-27 16:31:10 +08:00
|
|
|
/// are needed.
|
|
|
|
static void
|
|
|
|
HowToPassCCCArgument(MVT::ValueType ObjectVT, unsigned NumXMMRegs,
|
|
|
|
unsigned &ObjSize, unsigned &ObjXMMRegs) {
|
2006-06-01 13:53:27 +08:00
|
|
|
ObjXMMRegs = 0;
|
2006-05-26 07:31:23 +08:00
|
|
|
|
2006-04-27 09:32:22 +08:00
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8: ObjSize = 1; break;
|
|
|
|
case MVT::i16: ObjSize = 2; break;
|
|
|
|
case MVT::i32: ObjSize = 4; break;
|
|
|
|
case MVT::i64: ObjSize = 8; break;
|
|
|
|
case MVT::f32: ObjSize = 4; break;
|
|
|
|
case MVT::f64: ObjSize = 8; break;
|
2006-04-27 16:31:10 +08:00
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
2006-05-27 03:22:06 +08:00
|
|
|
if (NumXMMRegs < 4)
|
2006-04-27 16:31:10 +08:00
|
|
|
ObjXMMRegs = 1;
|
|
|
|
else
|
|
|
|
ObjSize = 16;
|
|
|
|
break;
|
2006-04-27 09:32:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
SDOperand X86TargetLowering::LowerCCCArguments(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
unsigned NumArgs = Op.Val->getNumValues() - 1;
|
2006-04-26 09:20:17 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
2006-05-24 05:06:34 +08:00
|
|
|
SDOperand Root = Op.getOperand(0);
|
|
|
|
std::vector<SDOperand> ArgValues;
|
2006-04-26 09:20:17 +08:00
|
|
|
|
2006-04-27 09:32:22 +08:00
|
|
|
// Add DAG nodes to load the arguments... On entry to a function on the X86,
|
|
|
|
// the stack frame looks like this:
|
|
|
|
//
|
|
|
|
// [ESP] -- return address
|
|
|
|
// [ESP + 4] -- first argument (leftmost lexically)
|
2006-05-27 02:37:16 +08:00
|
|
|
// [ESP + 8] -- second argument, if first argument is <= 4 bytes in size
|
2006-04-27 09:32:22 +08:00
|
|
|
// ...
|
|
|
|
//
|
2006-04-26 09:20:17 +08:00
|
|
|
unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
|
2006-04-27 16:31:10 +08:00
|
|
|
unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
|
2006-05-27 03:22:06 +08:00
|
|
|
static const unsigned XMMArgRegs[] = {
|
|
|
|
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
|
|
|
|
};
|
2006-04-26 09:20:17 +08:00
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
2006-05-24 05:06:34 +08:00
|
|
|
MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
|
|
|
|
unsigned ArgIncrement = 4;
|
|
|
|
unsigned ObjSize = 0;
|
|
|
|
unsigned ObjXMMRegs = 0;
|
|
|
|
HowToPassCCCArgument(ObjectVT, NumXMMRegs, ObjSize, ObjXMMRegs);
|
2006-05-27 02:39:59 +08:00
|
|
|
if (ObjSize > 4)
|
2006-05-24 05:06:34 +08:00
|
|
|
ArgIncrement = ObjSize;
|
|
|
|
|
|
|
|
SDOperand ArgValue;
|
|
|
|
if (ObjXMMRegs) {
|
|
|
|
// Passed in a XMM register.
|
|
|
|
unsigned Reg = AddLiveIn(MF, XMMArgRegs[NumXMMRegs],
|
2006-09-08 14:48:29 +08:00
|
|
|
X86::VR128RegisterClass);
|
2006-05-24 05:06:34 +08:00
|
|
|
ArgValue= DAG.getCopyFromReg(Root, Reg, ObjectVT);
|
|
|
|
ArgValues.push_back(ArgValue);
|
|
|
|
NumXMMRegs += ObjXMMRegs;
|
|
|
|
} else {
|
2006-05-27 04:37:47 +08:00
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
if (ObjSize == 16)
|
|
|
|
ArgOffset = ((ArgOffset + 15) / 16) * 16;
|
2006-05-24 05:06:34 +08:00
|
|
|
// Create the frame index object for this incoming parameter...
|
|
|
|
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
|
|
|
|
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
ArgValues.push_back(ArgValue);
|
|
|
|
ArgOffset += ArgIncrement; // Move on to the next argument...
|
2006-04-26 09:20:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
ArgValues.push_back(Root);
|
|
|
|
|
2006-04-26 09:20:17 +08:00
|
|
|
// If the function takes variable number of arguments, make a frame index for
|
|
|
|
// the start of the first vararg value... for expansion of llvm.va_start.
|
2006-05-24 05:08:24 +08:00
|
|
|
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
|
|
|
|
if (isVarArg)
|
2006-04-26 09:20:17 +08:00
|
|
|
VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
|
2006-09-08 14:48:29 +08:00
|
|
|
RegSaveFrameIndex = 0xAAAAAAA; // X86-64 only.
|
|
|
|
ReturnAddrIndex = 0; // No return address slot generated yet.
|
|
|
|
BytesToPopOnReturn = 0; // Callee pops nothing.
|
2006-04-26 09:20:17 +08:00
|
|
|
BytesCallerReserves = ArgOffset;
|
2006-05-24 05:06:34 +08:00
|
|
|
|
Implement an annoying part of the Darwin/X86 abi: the callee of a struct
return argument pops the hidden struct pointer if present, not the caller.
For example, in this testcase:
struct X { int D, E, F, G; };
struct X bar() {
struct X a;
a.D = 0;
a.E = 1;
a.F = 2;
a.G = 3;
return a;
}
void foo(struct X *P) {
*P = bar();
}
We used to emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
addl $28, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
ret
This is correct on Linux/X86 but not Darwin/X86. With this patch, we now
emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
*** addl $24, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
*** ret $4
For the record, GCC emits (which is functionally equivalent to our new code):
_bar:
movl 4(%esp), %eax
movl $3, 12(%eax)
movl $2, 8(%eax)
movl $1, 4(%eax)
movl $0, (%eax)
ret $4
_foo:
pushl %esi
subl $40, %esp
movl 48(%esp), %esi
leal 16(%esp), %eax
movl %eax, (%esp)
call _bar
subl $4, %esp
movl 16(%esp), %eax
movl %eax, (%esi)
movl 20(%esp), %eax
movl %eax, 4(%esi)
movl 24(%esp), %eax
movl %eax, 8(%esi)
movl 28(%esp), %eax
movl %eax, 12(%esi)
addl $40, %esp
popl %esi
ret
This fixes SingleSource/Benchmarks/CoyoteBench/fftbench with LLC and the
JIT, and fixes the X86-backend portion of PR729. The CBE still needs to
be updated.
llvm-svn: 28438
2006-05-24 02:50:38 +08:00
|
|
|
// If this is a struct return on Darwin/X86, the callee pops the hidden struct
|
|
|
|
// pointer.
|
2006-05-24 05:06:34 +08:00
|
|
|
if (MF.getFunction()->getCallingConv() == CallingConv::CSRet &&
|
Implement an annoying part of the Darwin/X86 abi: the callee of a struct
return argument pops the hidden struct pointer if present, not the caller.
For example, in this testcase:
struct X { int D, E, F, G; };
struct X bar() {
struct X a;
a.D = 0;
a.E = 1;
a.F = 2;
a.G = 3;
return a;
}
void foo(struct X *P) {
*P = bar();
}
We used to emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
addl $28, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
ret
This is correct on Linux/X86 but not Darwin/X86. With this patch, we now
emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
*** addl $24, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
*** ret $4
For the record, GCC emits (which is functionally equivalent to our new code):
_bar:
movl 4(%esp), %eax
movl $3, 12(%eax)
movl $2, 8(%eax)
movl $1, 4(%eax)
movl $0, (%eax)
ret $4
_foo:
pushl %esi
subl $40, %esp
movl 48(%esp), %esi
leal 16(%esp), %eax
movl %eax, (%esp)
call _bar
subl $4, %esp
movl 16(%esp), %eax
movl %eax, (%esi)
movl 20(%esp), %eax
movl %eax, 4(%esi)
movl 24(%esp), %eax
movl %eax, 8(%esi)
movl 28(%esp), %eax
movl %eax, 12(%esi)
addl $40, %esp
popl %esi
ret
This fixes SingleSource/Benchmarks/CoyoteBench/fftbench with LLC and the
JIT, and fixes the X86-backend portion of PR729. The CBE still needs to
be updated.
llvm-svn: 28438
2006-05-24 02:50:38 +08:00
|
|
|
Subtarget->isTargetDarwin())
|
|
|
|
BytesToPopOnReturn = 4;
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
// Return the new list of results.
|
|
|
|
std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
|
|
|
|
Op.Val->value_end());
|
2006-08-08 10:23:42 +08:00
|
|
|
return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand Chain = Op.getOperand(0);
|
|
|
|
unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
|
|
|
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
|
|
|
|
bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
|
|
|
|
SDOperand Callee = Op.getOperand(4);
|
|
|
|
MVT::ValueType RetVT= Op.Val->getValueType(0);
|
|
|
|
unsigned NumOps = (Op.getNumOperands() - 5) / 2;
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-04-29 05:29:37 +08:00
|
|
|
// Keep track of the number of XMM regs passed so far.
|
|
|
|
unsigned NumXMMRegs = 0;
|
2006-05-25 08:59:30 +08:00
|
|
|
static const unsigned XMMArgRegs[] = {
|
2006-05-27 03:22:06 +08:00
|
|
|
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
|
2006-05-25 08:59:30 +08:00
|
|
|
};
|
2006-04-29 05:29:37 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
// Count how many bytes are to be pushed on the stack.
|
|
|
|
unsigned NumBytes = 0;
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
switch (Arg.getValueType()) {
|
|
|
|
default: assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::f32:
|
|
|
|
NumBytes += 4;
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
case MVT::f64:
|
|
|
|
NumBytes += 8;
|
|
|
|
break;
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
2006-05-26 06:38:31 +08:00
|
|
|
case MVT::v2f64:
|
2006-05-27 03:22:06 +08:00
|
|
|
if (NumXMMRegs < 4)
|
2006-05-25 08:59:30 +08:00
|
|
|
++NumXMMRegs;
|
2006-05-27 04:37:47 +08:00
|
|
|
else {
|
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
NumBytes = ((NumBytes + 15) / 16) * 16;
|
2006-05-25 08:59:30 +08:00
|
|
|
NumBytes += 16;
|
2006-05-27 04:37:47 +08:00
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
|
|
|
|
// Arguments go on the stack in reverse order, as specified by the ABI.
|
|
|
|
unsigned ArgOffset = 0;
|
|
|
|
NumXMMRegs = 0;
|
|
|
|
std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
|
|
|
|
std::vector<SDOperand> MemOpChains;
|
2006-09-08 14:48:29 +08:00
|
|
|
SDOperand StackPtr = DAG.getRegister(X86StackPtr, getPointerTy());
|
2006-05-25 08:59:30 +08:00
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
|
|
|
|
|
|
|
switch (Arg.getValueType()) {
|
|
|
|
default: assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
case MVT::i8:
|
2006-05-26 02:56:34 +08:00
|
|
|
case MVT::i16: {
|
2006-05-25 08:59:30 +08:00
|
|
|
// Promote the integer to 32 bits. If the input type is signed use a
|
|
|
|
// sign extend, otherwise use a zero extend.
|
|
|
|
unsigned ExtOp =
|
|
|
|
dyn_cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue() ?
|
|
|
|
ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
|
|
|
|
Arg = DAG.getNode(ExtOp, MVT::i32, Arg);
|
2006-05-26 02:56:34 +08:00
|
|
|
}
|
|
|
|
// Fallthrough
|
2006-05-25 08:59:30 +08:00
|
|
|
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::f32: {
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
ArgOffset += 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MVT::i64:
|
|
|
|
case MVT::f64: {
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
ArgOffset += 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
2006-05-26 06:38:31 +08:00
|
|
|
case MVT::v2f64:
|
2006-05-27 03:22:06 +08:00
|
|
|
if (NumXMMRegs < 4) {
|
2006-05-25 08:59:30 +08:00
|
|
|
RegsToPass.push_back(std::make_pair(XMMArgRegs[NumXMMRegs], Arg));
|
|
|
|
NumXMMRegs++;
|
|
|
|
} else {
|
2006-05-27 04:37:47 +08:00
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
ArgOffset = ((ArgOffset + 15) / 16) * 16;
|
2006-04-29 05:29:37 +08:00
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
2006-05-25 08:59:30 +08:00
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
ArgOffset += 16;
|
2006-04-29 05:29:37 +08:00
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
if (!MemOpChains.empty())
|
2006-08-08 10:23:42 +08:00
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
|
|
|
|
&MemOpChains[0], MemOpChains.size());
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-04-29 05:29:37 +08:00
|
|
|
// Build a sequence of copy-to-reg nodes chained together with token chain
|
|
|
|
// and flag operands which copy the outgoing args into registers.
|
|
|
|
SDOperand InFlag;
|
2006-05-25 08:59:30 +08:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
|
|
|
|
InFlag);
|
2006-04-29 05:29:37 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
}
|
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
|
|
|
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
|
|
|
|
else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
|
|
|
|
|
2006-02-17 08:03:04 +08:00
|
|
|
std::vector<MVT::ValueType> NodeTys;
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
2006-06-15 02:17:40 +08:00
|
|
|
|
|
|
|
// Add argument registers to the end of the list so that they are known live
|
|
|
|
// into the call.
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
|
|
|
|
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
|
|
|
|
RegsToPass[i].second.getValueType()));
|
|
|
|
|
2006-04-29 05:29:37 +08:00
|
|
|
if (InFlag.Val)
|
|
|
|
Ops.push_back(InFlag);
|
2006-02-17 08:03:04 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
Chain = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
|
2006-08-08 10:23:42 +08:00
|
|
|
NodeTys, &Ops[0], Ops.size());
|
2006-04-29 05:29:37 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2006-02-17 08:03:04 +08:00
|
|
|
|
Implement an annoying part of the Darwin/X86 abi: the callee of a struct
return argument pops the hidden struct pointer if present, not the caller.
For example, in this testcase:
struct X { int D, E, F, G; };
struct X bar() {
struct X a;
a.D = 0;
a.E = 1;
a.F = 2;
a.G = 3;
return a;
}
void foo(struct X *P) {
*P = bar();
}
We used to emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
addl $28, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
ret
This is correct on Linux/X86 but not Darwin/X86. With this patch, we now
emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
*** addl $24, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
*** ret $4
For the record, GCC emits (which is functionally equivalent to our new code):
_bar:
movl 4(%esp), %eax
movl $3, 12(%eax)
movl $2, 8(%eax)
movl $1, 4(%eax)
movl $0, (%eax)
ret $4
_foo:
pushl %esi
subl $40, %esp
movl 48(%esp), %esi
leal 16(%esp), %eax
movl %eax, (%esp)
call _bar
subl $4, %esp
movl 16(%esp), %eax
movl %eax, (%esi)
movl 20(%esp), %eax
movl %eax, 4(%esi)
movl 24(%esp), %eax
movl %eax, 8(%esi)
movl 28(%esp), %eax
movl %eax, 12(%esi)
addl $40, %esp
popl %esi
ret
This fixes SingleSource/Benchmarks/CoyoteBench/fftbench with LLC and the
JIT, and fixes the X86-backend portion of PR729. The CBE still needs to
be updated.
llvm-svn: 28438
2006-05-24 02:50:38 +08:00
|
|
|
// Create the CALLSEQ_END node.
|
|
|
|
unsigned NumBytesForCalleeToPush = 0;
|
|
|
|
|
|
|
|
// If this is is a call to a struct-return function on Darwin/X86, the callee
|
|
|
|
// pops the hidden struct pointer, so we have to push it back.
|
|
|
|
if (CallingConv == CallingConv::CSRet && Subtarget->isTargetDarwin())
|
|
|
|
NumBytesForCalleeToPush = 4;
|
|
|
|
|
2006-02-17 08:03:04 +08:00
|
|
|
NodeTys.clear();
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
2006-05-25 08:59:30 +08:00
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
|
Implement an annoying part of the Darwin/X86 abi: the callee of a struct
return argument pops the hidden struct pointer if present, not the caller.
For example, in this testcase:
struct X { int D, E, F, G; };
struct X bar() {
struct X a;
a.D = 0;
a.E = 1;
a.F = 2;
a.G = 3;
return a;
}
void foo(struct X *P) {
*P = bar();
}
We used to emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
addl $28, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
ret
This is correct on Linux/X86 but not Darwin/X86. With this patch, we now
emit:
_foo:
subl $28, %esp
movl 32(%esp), %eax
movl %eax, (%esp)
call _bar
*** addl $24, %esp
ret
_bar:
movl 4(%esp), %eax
movl $0, (%eax)
movl $1, 4(%eax)
movl $2, 8(%eax)
movl $3, 12(%eax)
*** ret $4
For the record, GCC emits (which is functionally equivalent to our new code):
_bar:
movl 4(%esp), %eax
movl $3, 12(%eax)
movl $2, 8(%eax)
movl $1, 4(%eax)
movl $0, (%eax)
ret $4
_foo:
pushl %esi
subl $40, %esp
movl 48(%esp), %esi
leal 16(%esp), %eax
movl %eax, (%esp)
call _bar
subl $4, %esp
movl 16(%esp), %eax
movl %eax, (%esi)
movl 20(%esp), %eax
movl %eax, 4(%esi)
movl 24(%esp), %eax
movl %eax, 8(%esi)
movl 28(%esp), %eax
movl %eax, 12(%esi)
addl $40, %esp
popl %esi
ret
This fixes SingleSource/Benchmarks/CoyoteBench/fftbench with LLC and the
JIT, and fixes the X86-backend portion of PR729. The CBE still needs to
be updated.
llvm-svn: 28438
2006-05-24 02:50:38 +08:00
|
|
|
Ops.push_back(DAG.getConstant(NumBytesForCalleeToPush, getPointerTy()));
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.push_back(InFlag);
|
2006-08-08 10:23:42 +08:00
|
|
|
Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
InFlag = Chain.getValue(1);
|
2006-02-17 08:03:04 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
std::vector<SDOperand> ResultVals;
|
|
|
|
NodeTys.clear();
|
|
|
|
switch (RetVT) {
|
|
|
|
default: assert(0 && "Unknown value type to return!");
|
|
|
|
case MVT::Other: break;
|
|
|
|
case MVT::i8:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i8);
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i16);
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
if (Op.Val->getValueType(1) == MVT::i32) {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EDX, MVT::i32,
|
|
|
|
Chain.getValue(2)).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i32);
|
|
|
|
} else {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
2006-01-05 08:27:02 +08:00
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
NodeTys.push_back(MVT::i32);
|
|
|
|
break;
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::XMM0, RetVT, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(RetVT);
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64: {
|
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::f64);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(InFlag);
|
2006-08-08 10:23:42 +08:00
|
|
|
SDOperand RetVal = DAG.getNode(X86ISD::FP_GET_RESULT, Tys,
|
|
|
|
&Ops[0], Ops.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
Chain = RetVal.getValue(1);
|
|
|
|
InFlag = RetVal.getValue(2);
|
|
|
|
if (X86ScalarSSE) {
|
|
|
|
// FIXME: Currently the FST is flagged to the FP_GET_RESULT. This
|
|
|
|
// shouldn't be necessary except that RFP cannot be live across
|
|
|
|
// multiple blocks. When stackifier is fixed, they can be uncoupled.
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8);
|
|
|
|
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
|
|
|
|
Tys.clear();
|
2006-02-17 08:03:04 +08:00
|
|
|
Tys.push_back(MVT::Other);
|
2006-05-25 08:59:30 +08:00
|
|
|
Ops.clear();
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.push_back(Chain);
|
2006-05-25 08:59:30 +08:00
|
|
|
Ops.push_back(RetVal);
|
|
|
|
Ops.push_back(StackSlot);
|
|
|
|
Ops.push_back(DAG.getValueType(RetVT));
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.push_back(InFlag);
|
2006-08-08 10:23:42 +08:00
|
|
|
Chain = DAG.getNode(X86ISD::FST, Tys, &Ops[0], Ops.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
RetVal = DAG.getLoad(RetVT, Chain, StackSlot,
|
|
|
|
DAG.getSrcValue(NULL));
|
2006-04-29 05:29:37 +08:00
|
|
|
Chain = RetVal.getValue(1);
|
2006-02-17 08:03:04 +08:00
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
|
|
|
|
if (RetVT == MVT::f32 && !X86ScalarSSE)
|
|
|
|
// FIXME: we would really like to remember that this FP_ROUND
|
|
|
|
// operation is okay to eliminate if we allow excess FP precision.
|
|
|
|
RetVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, RetVal);
|
|
|
|
ResultVals.push_back(RetVal);
|
|
|
|
NodeTys.push_back(RetVT);
|
|
|
|
break;
|
|
|
|
}
|
2006-01-05 08:27:02 +08:00
|
|
|
}
|
2006-02-17 08:03:04 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
// If the function returns void, just return the chain.
|
|
|
|
if (ResultVals.empty())
|
|
|
|
return Chain;
|
|
|
|
|
|
|
|
// Otherwise, merge everything together with a MERGE_VALUES node.
|
|
|
|
NodeTys.push_back(MVT::Other);
|
|
|
|
ResultVals.push_back(Chain);
|
2006-08-08 10:23:42 +08:00
|
|
|
SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys,
|
|
|
|
&ResultVals[0], ResultVals.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
return Res.getValue(Op.ResNo);
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// X86-64 C Calling Convention implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// HowToPassX86_64CCCArgument - Returns how an formal argument of the specified
|
|
|
|
/// type should be passed. If it is through stack, returns the size of the stack
|
|
|
|
/// slot; if it is through integer or XMM register, returns the number of
|
|
|
|
/// integer or XMM registers are needed.
|
|
|
|
static void
|
|
|
|
HowToPassX86_64CCCArgument(MVT::ValueType ObjectVT,
|
|
|
|
unsigned NumIntRegs, unsigned NumXMMRegs,
|
|
|
|
unsigned &ObjSize, unsigned &ObjIntRegs,
|
|
|
|
unsigned &ObjXMMRegs) {
|
|
|
|
ObjSize = 0;
|
|
|
|
ObjIntRegs = 0;
|
|
|
|
ObjXMMRegs = 0;
|
|
|
|
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::i64:
|
|
|
|
if (NumIntRegs < 6)
|
|
|
|
ObjIntRegs = 1;
|
|
|
|
else {
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: break;
|
|
|
|
case MVT::i8: ObjSize = 1; break;
|
|
|
|
case MVT::i16: ObjSize = 2; break;
|
|
|
|
case MVT::i32: ObjSize = 4; break;
|
|
|
|
case MVT::i64: ObjSize = 8; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
|
|
|
if (NumXMMRegs < 8)
|
|
|
|
ObjXMMRegs = 1;
|
|
|
|
else {
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: break;
|
|
|
|
case MVT::f32: ObjSize = 4; break;
|
|
|
|
case MVT::f64: ObjSize = 8; break;
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64: ObjSize = 16; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerX86_64CCCArguments(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
unsigned NumArgs = Op.Val->getNumValues() - 1;
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
|
|
SDOperand Root = Op.getOperand(0);
|
|
|
|
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
|
|
|
|
std::vector<SDOperand> ArgValues;
|
|
|
|
|
|
|
|
// Add DAG nodes to load the arguments... On entry to a function on the X86,
|
|
|
|
// the stack frame looks like this:
|
|
|
|
//
|
|
|
|
// [RSP] -- return address
|
|
|
|
// [RSP + 8] -- first nonreg argument (leftmost lexically)
|
|
|
|
// [RSP +16] -- second nonreg argument, if 1st argument is <= 8 bytes in size
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
|
|
|
|
unsigned NumIntRegs = 0; // Int regs used for parameter passing.
|
|
|
|
unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
|
|
|
|
|
|
|
|
static const unsigned GPR8ArgRegs[] = {
|
|
|
|
X86::DIL, X86::SIL, X86::DL, X86::CL, X86::R8B, X86::R9B
|
|
|
|
};
|
|
|
|
static const unsigned GPR16ArgRegs[] = {
|
|
|
|
X86::DI, X86::SI, X86::DX, X86::CX, X86::R8W, X86::R9W
|
|
|
|
};
|
|
|
|
static const unsigned GPR32ArgRegs[] = {
|
|
|
|
X86::EDI, X86::ESI, X86::EDX, X86::ECX, X86::R8D, X86::R9D
|
|
|
|
};
|
|
|
|
static const unsigned GPR64ArgRegs[] = {
|
|
|
|
X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9
|
|
|
|
};
|
|
|
|
static const unsigned XMMArgRegs[] = {
|
|
|
|
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
|
|
|
|
X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7
|
|
|
|
};
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
|
|
|
MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
|
|
|
|
unsigned ArgIncrement = 8;
|
|
|
|
unsigned ObjSize = 0;
|
|
|
|
unsigned ObjIntRegs = 0;
|
|
|
|
unsigned ObjXMMRegs = 0;
|
|
|
|
|
|
|
|
// FIXME: __int128 and long double support?
|
|
|
|
HowToPassX86_64CCCArgument(ObjectVT, NumIntRegs, NumXMMRegs,
|
|
|
|
ObjSize, ObjIntRegs, ObjXMMRegs);
|
|
|
|
if (ObjSize > 8)
|
|
|
|
ArgIncrement = ObjSize;
|
|
|
|
|
|
|
|
unsigned Reg = 0;
|
|
|
|
SDOperand ArgValue;
|
|
|
|
if (ObjIntRegs || ObjXMMRegs) {
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::i64: {
|
|
|
|
TargetRegisterClass *RC = NULL;
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: break;
|
|
|
|
case MVT::i8:
|
|
|
|
RC = X86::GR8RegisterClass;
|
|
|
|
Reg = GPR8ArgRegs[NumIntRegs];
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
RC = X86::GR16RegisterClass;
|
|
|
|
Reg = GPR16ArgRegs[NumIntRegs];
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
RC = X86::GR32RegisterClass;
|
|
|
|
Reg = GPR32ArgRegs[NumIntRegs];
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
RC = X86::GR64RegisterClass;
|
|
|
|
Reg = GPR64ArgRegs[NumIntRegs];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Reg = AddLiveIn(MF, Reg, RC);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, ObjectVT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64: {
|
|
|
|
TargetRegisterClass *RC= (ObjectVT == MVT::f32) ?
|
|
|
|
X86::FR32RegisterClass : ((ObjectVT == MVT::f64) ?
|
|
|
|
X86::FR64RegisterClass : X86::VR128RegisterClass);
|
|
|
|
Reg = AddLiveIn(MF, XMMArgRegs[NumXMMRegs], RC);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, ObjectVT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NumIntRegs += ObjIntRegs;
|
|
|
|
NumXMMRegs += ObjXMMRegs;
|
|
|
|
} else if (ObjSize) {
|
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
if (ObjSize == 16)
|
|
|
|
ArgOffset = ((ArgOffset + 15) / 16) * 16;
|
|
|
|
// Create the SelectionDAG nodes corresponding to a load from this
|
|
|
|
// parameter.
|
|
|
|
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
|
|
|
|
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
ArgOffset += ArgIncrement; // Move on to the next argument.
|
|
|
|
}
|
|
|
|
|
|
|
|
ArgValues.push_back(ArgValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the function takes variable number of arguments, make a frame index for
|
|
|
|
// the start of the first vararg value... for expansion of llvm.va_start.
|
|
|
|
if (isVarArg) {
|
|
|
|
// For X86-64, if there are vararg parameters that are passed via
|
|
|
|
// registers, then we must store them to their spots on the stack so they
|
|
|
|
// may be loaded by deferencing the result of va_next.
|
|
|
|
VarArgsGPOffset = NumIntRegs * 8;
|
|
|
|
VarArgsFPOffset = 6 * 8 + NumXMMRegs * 16;
|
|
|
|
VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
|
|
|
|
RegSaveFrameIndex = MFI->CreateStackObject(6 * 8 + 8 * 16, 16);
|
|
|
|
|
|
|
|
// Store the integer parameter registers.
|
|
|
|
std::vector<SDOperand> MemOps;
|
|
|
|
SDOperand RSFIN = DAG.getFrameIndex(RegSaveFrameIndex, getPointerTy());
|
|
|
|
SDOperand FIN = DAG.getNode(ISD::ADD, getPointerTy(), RSFIN,
|
|
|
|
DAG.getConstant(VarArgsGPOffset, getPointerTy()));
|
|
|
|
for (; NumIntRegs != 6; ++NumIntRegs) {
|
|
|
|
unsigned VReg = AddLiveIn(MF, GPR64ArgRegs[NumIntRegs],
|
|
|
|
X86::GR64RegisterClass);
|
|
|
|
SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i64);
|
|
|
|
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1),
|
|
|
|
Val, FIN, DAG.getSrcValue(NULL));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
|
|
|
|
DAG.getConstant(8, getPointerTy()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now store the XMM (fp + vector) parameter registers.
|
|
|
|
FIN = DAG.getNode(ISD::ADD, getPointerTy(), RSFIN,
|
|
|
|
DAG.getConstant(VarArgsFPOffset, getPointerTy()));
|
|
|
|
for (; NumXMMRegs != 8; ++NumXMMRegs) {
|
|
|
|
unsigned VReg = AddLiveIn(MF, XMMArgRegs[NumXMMRegs],
|
|
|
|
X86::VR128RegisterClass);
|
|
|
|
SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::v4f32);
|
|
|
|
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1),
|
|
|
|
Val, FIN, DAG.getSrcValue(NULL));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
|
|
|
|
DAG.getConstant(16, getPointerTy()));
|
|
|
|
}
|
|
|
|
if (!MemOps.empty())
|
|
|
|
Root = DAG.getNode(ISD::TokenFactor, MVT::Other,
|
|
|
|
&MemOps[0], MemOps.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
ArgValues.push_back(Root);
|
|
|
|
|
|
|
|
ReturnAddrIndex = 0; // No return address slot generated yet.
|
|
|
|
BytesToPopOnReturn = 0; // Callee pops nothing.
|
|
|
|
BytesCallerReserves = ArgOffset;
|
|
|
|
|
|
|
|
// Return the new list of results.
|
|
|
|
std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
|
|
|
|
Op.Val->value_end());
|
|
|
|
return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerX86_64CCCCallTo(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand Chain = Op.getOperand(0);
|
|
|
|
unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
|
|
|
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
|
|
|
|
bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
|
|
|
|
SDOperand Callee = Op.getOperand(4);
|
|
|
|
MVT::ValueType RetVT= Op.Val->getValueType(0);
|
|
|
|
unsigned NumOps = (Op.getNumOperands() - 5) / 2;
|
|
|
|
|
|
|
|
// Count how many bytes are to be pushed on the stack.
|
|
|
|
unsigned NumBytes = 0;
|
|
|
|
unsigned NumIntRegs = 0; // Int regs used for parameter passing.
|
|
|
|
unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
|
|
|
|
|
|
|
|
static const unsigned GPR8ArgRegs[] = {
|
|
|
|
X86::DIL, X86::SIL, X86::DL, X86::CL, X86::R8B, X86::R9B
|
|
|
|
};
|
|
|
|
static const unsigned GPR16ArgRegs[] = {
|
|
|
|
X86::DI, X86::SI, X86::DX, X86::CX, X86::R8W, X86::R9W
|
|
|
|
};
|
|
|
|
static const unsigned GPR32ArgRegs[] = {
|
|
|
|
X86::EDI, X86::ESI, X86::EDX, X86::ECX, X86::R8D, X86::R9D
|
|
|
|
};
|
|
|
|
static const unsigned GPR64ArgRegs[] = {
|
|
|
|
X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9
|
|
|
|
};
|
|
|
|
static const unsigned XMMArgRegs[] = {
|
|
|
|
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
|
|
|
|
X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7
|
|
|
|
};
|
|
|
|
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
|
|
|
MVT::ValueType ArgVT = Arg.getValueType();
|
|
|
|
|
|
|
|
switch (ArgVT) {
|
|
|
|
default: assert(0 && "Unknown value type!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::i64:
|
|
|
|
if (NumIntRegs < 6)
|
|
|
|
++NumIntRegs;
|
|
|
|
else
|
|
|
|
NumBytes += 8;
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
|
|
|
if (NumXMMRegs < 8)
|
|
|
|
NumXMMRegs++;
|
|
|
|
else if (ArgVT == MVT::f32 || ArgVT == MVT::f64)
|
|
|
|
NumBytes += 8;
|
|
|
|
else {
|
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
NumBytes = ((NumBytes + 15) / 16) * 16;
|
|
|
|
NumBytes += 16;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
|
|
|
|
// Arguments go on the stack in reverse order, as specified by the ABI.
|
|
|
|
unsigned ArgOffset = 0;
|
|
|
|
NumIntRegs = 0;
|
|
|
|
NumXMMRegs = 0;
|
|
|
|
std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
|
|
|
|
std::vector<SDOperand> MemOpChains;
|
|
|
|
SDOperand StackPtr = DAG.getRegister(X86StackPtr, getPointerTy());
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
|
|
|
MVT::ValueType ArgVT = Arg.getValueType();
|
|
|
|
|
|
|
|
switch (ArgVT) {
|
|
|
|
default: assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::i64:
|
|
|
|
if (NumIntRegs < 6) {
|
|
|
|
unsigned Reg = 0;
|
|
|
|
switch (ArgVT) {
|
|
|
|
default: break;
|
|
|
|
case MVT::i8: Reg = GPR8ArgRegs[NumIntRegs]; break;
|
|
|
|
case MVT::i16: Reg = GPR16ArgRegs[NumIntRegs]; break;
|
|
|
|
case MVT::i32: Reg = GPR32ArgRegs[NumIntRegs]; break;
|
|
|
|
case MVT::i64: Reg = GPR64ArgRegs[NumIntRegs]; break;
|
|
|
|
}
|
|
|
|
RegsToPass.push_back(std::make_pair(Reg, Arg));
|
|
|
|
++NumIntRegs;
|
|
|
|
} else {
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
ArgOffset += 8;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
|
|
|
if (NumXMMRegs < 8) {
|
|
|
|
RegsToPass.push_back(std::make_pair(XMMArgRegs[NumXMMRegs], Arg));
|
|
|
|
NumXMMRegs++;
|
|
|
|
} else {
|
|
|
|
if (ArgVT != MVT::f32 && ArgVT != MVT::f64) {
|
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
ArgOffset = ((ArgOffset + 15) / 16) * 16;
|
|
|
|
}
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
if (ArgVT == MVT::f32 || ArgVT == MVT::f64)
|
|
|
|
ArgOffset += 8;
|
|
|
|
else
|
|
|
|
ArgOffset += 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!MemOpChains.empty())
|
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
|
|
|
|
&MemOpChains[0], MemOpChains.size());
|
|
|
|
|
|
|
|
// Build a sequence of copy-to-reg nodes chained together with token chain
|
|
|
|
// and flag operands which copy the outgoing args into registers.
|
|
|
|
SDOperand InFlag;
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
|
|
|
|
InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isVarArg) {
|
|
|
|
// From AMD64 ABI document:
|
|
|
|
// For calls that may call functions that use varargs or stdargs
|
|
|
|
// (prototype-less calls or calls to functions containing ellipsis (...) in
|
|
|
|
// the declaration) %al is used as hidden argument to specify the number
|
|
|
|
// of SSE registers used. The contents of %al do not need to match exactly
|
|
|
|
// the number of registers, but must be an ubound on the number of SSE
|
|
|
|
// registers used and is in the range 0 - 8 inclusive.
|
|
|
|
Chain = DAG.getCopyToReg(Chain, X86::AL,
|
|
|
|
DAG.getConstant(NumXMMRegs, MVT::i8), InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
|
|
|
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
|
|
|
|
else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
|
|
|
|
|
|
|
|
std::vector<MVT::ValueType> NodeTys;
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
|
|
|
|
|
|
|
// Add argument registers to the end of the list so that they are known live
|
|
|
|
// into the call.
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
|
|
|
|
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
|
|
|
|
RegsToPass[i].second.getValueType()));
|
|
|
|
|
|
|
|
if (InFlag.Val)
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
|
|
|
|
// FIXME: Do not generate X86ISD::TAILCALL for now.
|
|
|
|
Chain = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
|
|
|
|
NodeTys, &Ops[0], Ops.size());
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
|
|
|
NodeTys.clear();
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
Ops.push_back(DAG.getConstant(0, getPointerTy()));
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size());
|
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
|
|
|
std::vector<SDOperand> ResultVals;
|
|
|
|
NodeTys.clear();
|
|
|
|
switch (RetVT) {
|
|
|
|
default: assert(0 && "Unknown value type to return!");
|
|
|
|
case MVT::Other: break;
|
|
|
|
case MVT::i8:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i8);
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i16);
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i32);
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
if (Op.Val->getValueType(1) == MVT::i64) {
|
|
|
|
// FIXME: __int128 support?
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::RAX, MVT::i64, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::RDX, MVT::i64,
|
|
|
|
Chain.getValue(2)).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i64);
|
|
|
|
} else {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::RAX, MVT::i64, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
}
|
|
|
|
NodeTys.push_back(MVT::i64);
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
|
|
|
// FIXME: long double support?
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::XMM0, RetVT, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(RetVT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the function returns void, just return the chain.
|
|
|
|
if (ResultVals.empty())
|
|
|
|
return Chain;
|
|
|
|
|
|
|
|
// Otherwise, merge everything together with a MERGE_VALUES node.
|
|
|
|
NodeTys.push_back(MVT::Other);
|
|
|
|
ResultVals.push_back(Chain);
|
|
|
|
SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys,
|
|
|
|
&ResultVals[0], ResultVals.size());
|
|
|
|
return Res.getValue(Op.ResNo);
|
|
|
|
}
|
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Fast Calling Convention implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The X86 'fast' calling convention passes up to two integer arguments in
|
|
|
|
// registers (an appropriate portion of EAX/EDX), passes arguments in C order,
|
|
|
|
// and requires that the callee pop its arguments off the stack (allowing proper
|
|
|
|
// tail calls), and has the same return value conventions as C calling convs.
|
|
|
|
//
|
|
|
|
// This calling convention always arranges for the callee pop value to be 8n+4
|
|
|
|
// bytes, which is needed for tail recursion elimination and stack alignment
|
|
|
|
// reasons.
|
|
|
|
//
|
|
|
|
// Note that this can be enhanced in the future to pass fp vals in registers
|
|
|
|
// (when we have a global fp allocator) and do other tricks.
|
|
|
|
//
|
|
|
|
|
2006-04-27 16:31:10 +08:00
|
|
|
/// HowToPassFastCCArgument - Returns how an formal argument of the specified
|
|
|
|
/// type should be passed. If it is through stack, returns the size of the stack
|
2006-05-27 02:25:43 +08:00
|
|
|
/// slot; if it is through integer or XMM register, returns the number of
|
2006-04-27 16:31:10 +08:00
|
|
|
/// integer or XMM registers are needed.
|
2006-04-27 09:32:22 +08:00
|
|
|
static void
|
2006-04-27 16:31:10 +08:00
|
|
|
HowToPassFastCCArgument(MVT::ValueType ObjectVT,
|
|
|
|
unsigned NumIntRegs, unsigned NumXMMRegs,
|
|
|
|
unsigned &ObjSize, unsigned &ObjIntRegs,
|
|
|
|
unsigned &ObjXMMRegs) {
|
2006-04-27 09:32:22 +08:00
|
|
|
ObjSize = 0;
|
2006-06-01 13:53:27 +08:00
|
|
|
ObjIntRegs = 0;
|
|
|
|
ObjXMMRegs = 0;
|
2006-04-27 09:32:22 +08:00
|
|
|
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8:
|
2006-06-24 16:36:10 +08:00
|
|
|
#if FASTCC_NUM_INT_ARGS_INREGS > 0
|
2006-04-27 09:32:22 +08:00
|
|
|
if (NumIntRegs < FASTCC_NUM_INT_ARGS_INREGS)
|
2006-04-27 13:35:28 +08:00
|
|
|
ObjIntRegs = 1;
|
2006-04-27 09:32:22 +08:00
|
|
|
else
|
2006-06-24 16:36:10 +08:00
|
|
|
#endif
|
2006-04-27 09:32:22 +08:00
|
|
|
ObjSize = 1;
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
2006-06-24 16:36:10 +08:00
|
|
|
#if FASTCC_NUM_INT_ARGS_INREGS > 0
|
2006-04-27 09:32:22 +08:00
|
|
|
if (NumIntRegs < FASTCC_NUM_INT_ARGS_INREGS)
|
2006-04-27 13:35:28 +08:00
|
|
|
ObjIntRegs = 1;
|
2006-04-27 09:32:22 +08:00
|
|
|
else
|
2006-06-24 16:36:10 +08:00
|
|
|
#endif
|
2006-04-27 09:32:22 +08:00
|
|
|
ObjSize = 2;
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
2006-06-24 16:36:10 +08:00
|
|
|
#if FASTCC_NUM_INT_ARGS_INREGS > 0
|
2006-04-27 09:32:22 +08:00
|
|
|
if (NumIntRegs < FASTCC_NUM_INT_ARGS_INREGS)
|
2006-04-27 13:35:28 +08:00
|
|
|
ObjIntRegs = 1;
|
2006-04-27 09:32:22 +08:00
|
|
|
else
|
2006-06-24 16:36:10 +08:00
|
|
|
#endif
|
2006-04-27 09:32:22 +08:00
|
|
|
ObjSize = 4;
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
2006-06-24 16:36:10 +08:00
|
|
|
#if FASTCC_NUM_INT_ARGS_INREGS > 0
|
2006-04-27 09:32:22 +08:00
|
|
|
if (NumIntRegs+2 <= FASTCC_NUM_INT_ARGS_INREGS) {
|
2006-04-27 13:35:28 +08:00
|
|
|
ObjIntRegs = 2;
|
2006-04-27 09:32:22 +08:00
|
|
|
} else if (NumIntRegs+1 <= FASTCC_NUM_INT_ARGS_INREGS) {
|
2006-04-27 13:35:28 +08:00
|
|
|
ObjIntRegs = 1;
|
2006-04-27 09:32:22 +08:00
|
|
|
ObjSize = 4;
|
|
|
|
} else
|
2006-06-24 16:36:10 +08:00
|
|
|
#endif
|
2006-04-27 09:32:22 +08:00
|
|
|
ObjSize = 8;
|
|
|
|
case MVT::f32:
|
|
|
|
ObjSize = 4;
|
|
|
|
break;
|
|
|
|
case MVT::f64:
|
|
|
|
ObjSize = 8;
|
|
|
|
break;
|
2006-04-27 16:31:10 +08:00
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
2006-05-27 03:22:06 +08:00
|
|
|
if (NumXMMRegs < 4)
|
2006-04-27 16:31:10 +08:00
|
|
|
ObjXMMRegs = 1;
|
|
|
|
else
|
|
|
|
ObjSize = 16;
|
|
|
|
break;
|
2006-04-27 09:32:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
unsigned NumArgs = Op.Val->getNumValues()-1;
|
2006-04-26 09:20:17 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
2006-05-24 05:06:34 +08:00
|
|
|
SDOperand Root = Op.getOperand(0);
|
|
|
|
std::vector<SDOperand> ArgValues;
|
2006-04-26 09:20:17 +08:00
|
|
|
|
2006-04-27 09:32:22 +08:00
|
|
|
// Add DAG nodes to load the arguments... On entry to a function the stack
|
|
|
|
// frame looks like this:
|
|
|
|
//
|
|
|
|
// [ESP] -- return address
|
|
|
|
// [ESP + 4] -- first nonreg argument (leftmost lexically)
|
2006-05-27 02:37:16 +08:00
|
|
|
// [ESP + 8] -- second nonreg argument, if 1st argument is <= 4 bytes in size
|
2006-04-27 09:32:22 +08:00
|
|
|
// ...
|
2006-04-26 09:20:17 +08:00
|
|
|
unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
|
|
|
|
|
|
|
|
// Keep track of the number of integer regs passed so far. This can be either
|
|
|
|
// 0 (neither EAX or EDX used), 1 (EAX is used) or 2 (EAX and EDX are both
|
|
|
|
// used).
|
|
|
|
unsigned NumIntRegs = 0;
|
2006-04-27 16:31:10 +08:00
|
|
|
unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
|
2006-05-25 08:59:30 +08:00
|
|
|
|
|
|
|
static const unsigned XMMArgRegs[] = {
|
2006-05-27 03:22:06 +08:00
|
|
|
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
|
2006-05-25 08:59:30 +08:00
|
|
|
};
|
2006-04-26 09:20:17 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
2006-05-24 05:06:34 +08:00
|
|
|
MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
|
|
|
|
unsigned ArgIncrement = 4;
|
|
|
|
unsigned ObjSize = 0;
|
|
|
|
unsigned ObjIntRegs = 0;
|
|
|
|
unsigned ObjXMMRegs = 0;
|
|
|
|
|
|
|
|
HowToPassFastCCArgument(ObjectVT, NumIntRegs, NumXMMRegs,
|
|
|
|
ObjSize, ObjIntRegs, ObjXMMRegs);
|
2006-05-27 02:39:59 +08:00
|
|
|
if (ObjSize > 4)
|
2006-05-24 05:06:34 +08:00
|
|
|
ArgIncrement = ObjSize;
|
|
|
|
|
2006-06-01 08:30:39 +08:00
|
|
|
unsigned Reg = 0;
|
2006-05-24 05:06:34 +08:00
|
|
|
SDOperand ArgValue;
|
|
|
|
if (ObjIntRegs || ObjXMMRegs) {
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::DL : X86::AL,
|
|
|
|
X86::GR8RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i8);
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::DX : X86::AX,
|
|
|
|
X86::GR16RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i16);
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::EAX,
|
|
|
|
X86::GR32RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::EAX,
|
|
|
|
X86::GR32RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
|
|
|
|
if (ObjIntRegs == 2) {
|
|
|
|
Reg = AddLiveIn(MF, X86::EDX, X86::GR32RegisterClass);
|
|
|
|
SDOperand ArgValue2 = DAG.getCopyFromReg(Root, Reg, MVT::i32);
|
|
|
|
ArgValue= DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
|
2006-04-27 09:32:22 +08:00
|
|
|
}
|
2006-05-24 05:06:34 +08:00
|
|
|
break;
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
|
|
|
Reg = AddLiveIn(MF, XMMArgRegs[NumXMMRegs], X86::VR128RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, ObjectVT);
|
|
|
|
break;
|
2006-04-26 09:20:17 +08:00
|
|
|
}
|
2006-05-24 05:06:34 +08:00
|
|
|
NumIntRegs += ObjIntRegs;
|
|
|
|
NumXMMRegs += ObjXMMRegs;
|
|
|
|
}
|
2006-04-26 09:20:17 +08:00
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
if (ObjSize) {
|
2006-05-27 04:37:47 +08:00
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
if (ObjSize == 16)
|
|
|
|
ArgOffset = ((ArgOffset + 15) / 16) * 16;
|
2006-05-24 05:06:34 +08:00
|
|
|
// Create the SelectionDAG nodes corresponding to a load from this
|
|
|
|
// parameter.
|
|
|
|
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
|
|
|
|
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
if (ObjectVT == MVT::i64 && ObjIntRegs) {
|
|
|
|
SDOperand ArgValue2 = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
ArgValue = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
|
|
|
|
} else
|
|
|
|
ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
ArgOffset += ArgIncrement; // Move on to the next argument.
|
2006-04-27 09:32:22 +08:00
|
|
|
}
|
2006-05-24 05:06:34 +08:00
|
|
|
|
|
|
|
ArgValues.push_back(ArgValue);
|
2006-04-26 09:20:17 +08:00
|
|
|
}
|
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
ArgValues.push_back(Root);
|
|
|
|
|
2006-04-26 09:20:17 +08:00
|
|
|
// Make sure the instruction takes 8n+4 bytes to make sure the start of the
|
|
|
|
// arguments and the arguments after the retaddr has been pushed are aligned.
|
|
|
|
if ((ArgOffset & 7) == 0)
|
|
|
|
ArgOffset += 4;
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-04-26 09:20:17 +08:00
|
|
|
VarArgsFrameIndex = 0xAAAAAAA; // fastcc functions can't have varargs.
|
2006-09-08 14:48:29 +08:00
|
|
|
RegSaveFrameIndex = 0xAAAAAAA; // X86-64 only.
|
2006-04-26 09:20:17 +08:00
|
|
|
ReturnAddrIndex = 0; // No return address slot generated yet.
|
|
|
|
BytesToPopOnReturn = ArgOffset; // Callee pops all stack arguments.
|
|
|
|
BytesCallerReserves = 0;
|
|
|
|
|
|
|
|
// Finally, inform the code generator which regs we return values in.
|
2006-05-24 05:06:34 +08:00
|
|
|
switch (getValueType(MF.getFunction()->getReturnType())) {
|
2006-04-26 09:20:17 +08:00
|
|
|
default: assert(0 && "Unknown type!");
|
|
|
|
case MVT::isVoid: break;
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
MF.addLiveOut(X86::EAX);
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
MF.addLiveOut(X86::EAX);
|
|
|
|
MF.addLiveOut(X86::EDX);
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
MF.addLiveOut(X86::ST0);
|
|
|
|
break;
|
2006-05-26 02:56:34 +08:00
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
2006-04-29 05:29:37 +08:00
|
|
|
MF.addLiveOut(X86::XMM0);
|
|
|
|
break;
|
|
|
|
}
|
2006-05-17 01:08:35 +08:00
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
// Return the new list of results.
|
|
|
|
std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
|
|
|
|
Op.Val->value_end());
|
2006-08-08 10:23:42 +08:00
|
|
|
return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
2006-09-21 06:03:51 +08:00
|
|
|
SDOperand X86TargetLowering::LowerFastCCCallTo(SDOperand Op,
|
|
|
|
SelectionDAG &DAG,
|
|
|
|
bool isFastCall){
|
2006-05-25 08:59:30 +08:00
|
|
|
SDOperand Chain = Op.getOperand(0);
|
|
|
|
unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
|
|
|
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
|
|
|
|
bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
|
|
|
|
SDOperand Callee = Op.getOperand(4);
|
|
|
|
MVT::ValueType RetVT= Op.Val->getValueType(0);
|
|
|
|
unsigned NumOps = (Op.getNumOperands() - 5) / 2;
|
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
// Count how many bytes are to be pushed on the stack.
|
|
|
|
unsigned NumBytes = 0;
|
|
|
|
|
|
|
|
// Keep track of the number of integer regs passed so far. This can be either
|
|
|
|
// 0 (neither EAX or EDX used), 1 (EAX is used) or 2 (EAX and EDX are both
|
|
|
|
// used).
|
|
|
|
unsigned NumIntRegs = 0;
|
2006-05-25 08:59:30 +08:00
|
|
|
unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
|
|
|
|
|
|
|
|
static const unsigned GPRArgRegs[][2] = {
|
|
|
|
{ X86::AL, X86::DL },
|
|
|
|
{ X86::AX, X86::DX },
|
|
|
|
{ X86::EAX, X86::EDX }
|
|
|
|
};
|
2006-09-21 06:03:51 +08:00
|
|
|
static const unsigned FastCallGPRArgRegs[][2] = {
|
|
|
|
{ X86::CL, X86::DL },
|
|
|
|
{ X86::CX, X86::DX },
|
|
|
|
{ X86::ECX, X86::EDX }
|
|
|
|
};
|
2006-05-25 08:59:30 +08:00
|
|
|
static const unsigned XMMArgRegs[] = {
|
2006-05-27 03:22:06 +08:00
|
|
|
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
|
2006-05-25 08:59:30 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
switch (Arg.getValueType()) {
|
2005-11-15 08:40:23 +08:00
|
|
|
default: assert(0 && "Unknown value type!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
2006-09-21 06:03:51 +08:00
|
|
|
unsigned MaxNumIntRegs = (isFastCall ? 2 : FASTCC_NUM_INT_ARGS_INREGS);
|
|
|
|
if (NumIntRegs < MaxNumIntRegs) {
|
|
|
|
++NumIntRegs;
|
|
|
|
break;
|
|
|
|
}
|
2006-05-26 06:38:31 +08:00
|
|
|
// Fall through
|
2005-11-15 08:40:23 +08:00
|
|
|
case MVT::f32:
|
|
|
|
NumBytes += 4;
|
|
|
|
break;
|
|
|
|
case MVT::f64:
|
|
|
|
NumBytes += 8;
|
|
|
|
break;
|
2006-05-25 08:59:30 +08:00
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
2006-05-26 02:56:34 +08:00
|
|
|
case MVT::v2f64:
|
2006-09-21 06:03:51 +08:00
|
|
|
if (isFastCall) {
|
|
|
|
assert(0 && "Unknown value type!");
|
|
|
|
} else {
|
|
|
|
if (NumXMMRegs < 4)
|
|
|
|
NumXMMRegs++;
|
|
|
|
else {
|
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
NumBytes = ((NumBytes + 15) / 16) * 16;
|
|
|
|
NumBytes += 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2006-05-25 08:59:30 +08:00
|
|
|
}
|
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
|
|
|
|
// Make sure the instruction takes 8n+4 bytes to make sure the start of the
|
|
|
|
// arguments and the arguments after the retaddr has been pushed are aligned.
|
|
|
|
if ((NumBytes & 7) == 0)
|
|
|
|
NumBytes += 4;
|
|
|
|
|
2006-02-13 17:00:43 +08:00
|
|
|
Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes, getPointerTy()));
|
2005-11-15 08:40:23 +08:00
|
|
|
|
|
|
|
// Arguments go on the stack in reverse order, as specified by the ABI.
|
|
|
|
unsigned ArgOffset = 0;
|
|
|
|
NumIntRegs = 0;
|
2006-05-25 08:59:30 +08:00
|
|
|
std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
|
|
|
|
std::vector<SDOperand> MemOpChains;
|
2006-09-08 14:48:29 +08:00
|
|
|
SDOperand StackPtr = DAG.getRegister(X86StackPtr, getPointerTy());
|
2006-05-25 08:59:30 +08:00
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
|
|
|
|
|
|
|
switch (Arg.getValueType()) {
|
2005-11-15 08:40:23 +08:00
|
|
|
default: assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
2006-09-21 06:03:51 +08:00
|
|
|
unsigned MaxNumIntRegs = (isFastCall ? 2 : FASTCC_NUM_INT_ARGS_INREGS);
|
|
|
|
if (NumIntRegs < MaxNumIntRegs) {
|
|
|
|
RegsToPass.push_back(
|
|
|
|
std::make_pair(GPRArgRegs[Arg.getValueType()-MVT::i8][NumIntRegs],
|
|
|
|
Arg));
|
|
|
|
++NumIntRegs;
|
|
|
|
break;
|
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
// Fall through
|
|
|
|
case MVT::f32: {
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
2006-05-25 08:59:30 +08:00
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
2005-11-15 08:40:23 +08:00
|
|
|
ArgOffset += 4;
|
|
|
|
break;
|
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
case MVT::f64: {
|
2005-11-15 08:40:23 +08:00
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
2006-05-25 08:59:30 +08:00
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
2005-11-15 08:40:23 +08:00
|
|
|
ArgOffset += 8;
|
|
|
|
break;
|
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
2006-05-26 02:56:34 +08:00
|
|
|
case MVT::v2f64:
|
2006-09-21 06:03:51 +08:00
|
|
|
if (isFastCall) {
|
|
|
|
assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
} else {
|
|
|
|
if (NumXMMRegs < 4) {
|
|
|
|
RegsToPass.push_back(std::make_pair(XMMArgRegs[NumXMMRegs], Arg));
|
|
|
|
NumXMMRegs++;
|
|
|
|
} else {
|
|
|
|
// XMM arguments have to be aligned on 16-byte boundary.
|
|
|
|
ArgOffset = ((ArgOffset + 15) / 16) * 16;
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
ArgOffset += 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2006-05-25 08:59:30 +08:00
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
if (!MemOpChains.empty())
|
2006-08-08 10:23:42 +08:00
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
|
|
|
|
&MemOpChains[0], MemOpChains.size());
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-02-17 08:03:04 +08:00
|
|
|
// Build a sequence of copy-to-reg nodes chained together with token chain
|
|
|
|
// and flag operands which copy the outgoing args into registers.
|
|
|
|
SDOperand InFlag;
|
2006-05-25 08:59:30 +08:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
|
|
|
|
InFlag);
|
2006-01-06 08:43:03 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2006-02-17 08:03:04 +08:00
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
|
|
|
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
|
|
|
|
else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
|
|
|
|
|
2006-02-17 08:03:04 +08:00
|
|
|
std::vector<MVT::ValueType> NodeTys;
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
2006-06-15 02:17:40 +08:00
|
|
|
|
|
|
|
// Add argument registers to the end of the list so that they are known live
|
|
|
|
// into the call.
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
|
|
|
|
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
|
|
|
|
RegsToPass[i].second.getValueType()));
|
|
|
|
|
2006-02-17 08:03:04 +08:00
|
|
|
if (InFlag.Val)
|
2006-01-24 13:17:12 +08:00
|
|
|
Ops.push_back(InFlag);
|
2006-01-06 08:43:03 +08:00
|
|
|
|
2006-02-17 08:03:04 +08:00
|
|
|
// FIXME: Do not generate X86ISD::TAILCALL for now.
|
2006-05-16 14:45:34 +08:00
|
|
|
Chain = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
|
2006-08-08 10:23:42 +08:00
|
|
|
NodeTys, &Ops[0], Ops.size());
|
2006-02-17 08:03:04 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
|
|
|
NodeTys.clear();
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
2006-05-25 08:59:30 +08:00
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Chain);
|
2006-05-25 08:59:30 +08:00
|
|
|
Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.push_back(InFlag);
|
2006-08-08 10:23:42 +08:00
|
|
|
Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
InFlag = Chain.getValue(1);
|
2006-02-17 08:03:04 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
std::vector<SDOperand> ResultVals;
|
|
|
|
NodeTys.clear();
|
|
|
|
switch (RetVT) {
|
|
|
|
default: assert(0 && "Unknown value type to return!");
|
|
|
|
case MVT::Other: break;
|
|
|
|
case MVT::i8:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i8);
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i16);
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
if (Op.Val->getValueType(1) == MVT::i32) {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EDX, MVT::i32,
|
|
|
|
Chain.getValue(2)).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i32);
|
|
|
|
} else {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
2006-01-06 08:43:03 +08:00
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
NodeTys.push_back(MVT::i32);
|
|
|
|
break;
|
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
|
|
|
case MVT::v2i64:
|
|
|
|
case MVT::v4f32:
|
|
|
|
case MVT::v2f64:
|
2006-09-21 06:03:51 +08:00
|
|
|
if (isFastCall) {
|
|
|
|
assert(0 && "Unknown value type to return!");
|
|
|
|
} else {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::XMM0, RetVT, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(RetVT);
|
|
|
|
}
|
|
|
|
break;
|
2006-05-25 08:59:30 +08:00
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64: {
|
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::f64);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(InFlag);
|
2006-08-08 10:23:42 +08:00
|
|
|
SDOperand RetVal = DAG.getNode(X86ISD::FP_GET_RESULT, Tys,
|
|
|
|
&Ops[0], Ops.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
Chain = RetVal.getValue(1);
|
|
|
|
InFlag = RetVal.getValue(2);
|
|
|
|
if (X86ScalarSSE) {
|
|
|
|
// FIXME: Currently the FST is flagged to the FP_GET_RESULT. This
|
|
|
|
// shouldn't be necessary except that RFP cannot be live across
|
|
|
|
// multiple blocks. When stackifier is fixed, they can be uncoupled.
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8);
|
|
|
|
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
|
|
|
|
Tys.clear();
|
2006-02-17 08:03:04 +08:00
|
|
|
Tys.push_back(MVT::Other);
|
2006-05-25 08:59:30 +08:00
|
|
|
Ops.clear();
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.push_back(Chain);
|
2006-05-25 08:59:30 +08:00
|
|
|
Ops.push_back(RetVal);
|
|
|
|
Ops.push_back(StackSlot);
|
|
|
|
Ops.push_back(DAG.getValueType(RetVT));
|
2006-02-17 08:03:04 +08:00
|
|
|
Ops.push_back(InFlag);
|
2006-08-08 10:23:42 +08:00
|
|
|
Chain = DAG.getNode(X86ISD::FST, Tys, &Ops[0], Ops.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
RetVal = DAG.getLoad(RetVT, Chain, StackSlot,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
Chain = RetVal.getValue(1);
|
2006-02-17 08:03:04 +08:00
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
|
|
|
|
if (RetVT == MVT::f32 && !X86ScalarSSE)
|
|
|
|
// FIXME: we would really like to remember that this FP_ROUND
|
|
|
|
// operation is okay to eliminate if we allow excess FP precision.
|
|
|
|
RetVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, RetVal);
|
|
|
|
ResultVals.push_back(RetVal);
|
|
|
|
NodeTys.push_back(RetVT);
|
|
|
|
break;
|
|
|
|
}
|
2006-01-06 08:43:03 +08:00
|
|
|
}
|
2006-02-17 08:03:04 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
|
|
|
|
// If the function returns void, just return the chain.
|
|
|
|
if (ResultVals.empty())
|
|
|
|
return Chain;
|
|
|
|
|
|
|
|
// Otherwise, merge everything together with a MERGE_VALUES node.
|
|
|
|
NodeTys.push_back(MVT::Other);
|
|
|
|
ResultVals.push_back(Chain);
|
2006-08-08 10:23:42 +08:00
|
|
|
SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys,
|
|
|
|
&ResultVals[0], ResultVals.size());
|
2006-05-25 08:59:30 +08:00
|
|
|
return Res.getValue(Op.ResNo);
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
2006-09-21 06:03:51 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// StdCall Calling Convention implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// StdCall calling convention seems to be standard for many Windows' API
|
|
|
|
// routines and around. It differs from C calling convention just a little:
|
|
|
|
// callee should clean up the stack, not caller. Symbols should be also
|
|
|
|
// decorated in some fancy way :) It doesn't support any vector arguments.
|
|
|
|
|
|
|
|
/// HowToPassStdCallCCArgument - Returns how an formal argument of the specified
|
|
|
|
/// type should be passed. Returns the size of the stack slot
|
|
|
|
static void
|
|
|
|
HowToPassStdCallCCArgument(MVT::ValueType ObjectVT, unsigned &ObjSize) {
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8: ObjSize = 1; break;
|
|
|
|
case MVT::i16: ObjSize = 2; break;
|
|
|
|
case MVT::i32: ObjSize = 4; break;
|
|
|
|
case MVT::i64: ObjSize = 8; break;
|
|
|
|
case MVT::f32: ObjSize = 4; break;
|
|
|
|
case MVT::f64: ObjSize = 8; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerStdCallCCArguments(SDOperand Op,
|
|
|
|
SelectionDAG &DAG) {
|
|
|
|
unsigned NumArgs = Op.Val->getNumValues() - 1;
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
|
|
SDOperand Root = Op.getOperand(0);
|
|
|
|
std::vector<SDOperand> ArgValues;
|
|
|
|
|
|
|
|
// Add DAG nodes to load the arguments... On entry to a function on the X86,
|
|
|
|
// the stack frame looks like this:
|
|
|
|
//
|
|
|
|
// [ESP] -- return address
|
|
|
|
// [ESP + 4] -- first argument (leftmost lexically)
|
|
|
|
// [ESP + 8] -- second argument, if first argument is <= 4 bytes in size
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
|
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
|
|
|
MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
|
|
|
|
unsigned ArgIncrement = 4;
|
|
|
|
unsigned ObjSize = 0;
|
|
|
|
HowToPassStdCallCCArgument(ObjectVT, ObjSize);
|
|
|
|
if (ObjSize > 4)
|
|
|
|
ArgIncrement = ObjSize;
|
|
|
|
|
|
|
|
SDOperand ArgValue;
|
|
|
|
// Create the frame index object for this incoming parameter...
|
|
|
|
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
|
|
|
|
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
ArgValues.push_back(ArgValue);
|
|
|
|
ArgOffset += ArgIncrement; // Move on to the next argument...
|
|
|
|
}
|
|
|
|
|
|
|
|
ArgValues.push_back(Root);
|
|
|
|
|
|
|
|
// If the function takes variable number of arguments, make a frame index for
|
|
|
|
// the start of the first vararg value... for expansion of llvm.va_start.
|
|
|
|
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
|
|
|
|
if (isVarArg) {
|
|
|
|
BytesToPopOnReturn = 0; // Callee pops nothing.
|
|
|
|
BytesCallerReserves = ArgOffset;
|
|
|
|
VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
|
|
|
|
} else {
|
|
|
|
BytesToPopOnReturn = ArgOffset; // Callee pops everything..
|
|
|
|
BytesCallerReserves = 0;
|
|
|
|
}
|
|
|
|
RegSaveFrameIndex = 0xAAAAAAA; // X86-64 only.
|
|
|
|
ReturnAddrIndex = 0; // No return address slot generated yet.
|
|
|
|
|
|
|
|
MF.getInfo<X86FunctionInfo>()->setBytesToPopOnReturn(BytesToPopOnReturn);
|
|
|
|
|
|
|
|
// Return the new list of results.
|
|
|
|
std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
|
|
|
|
Op.Val->value_end());
|
|
|
|
return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerStdCallCCCallTo(SDOperand Op,
|
|
|
|
SelectionDAG &DAG) {
|
|
|
|
SDOperand Chain = Op.getOperand(0);
|
|
|
|
unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
|
|
|
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
|
|
|
|
bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
|
|
|
|
SDOperand Callee = Op.getOperand(4);
|
|
|
|
MVT::ValueType RetVT= Op.Val->getValueType(0);
|
|
|
|
unsigned NumOps = (Op.getNumOperands() - 5) / 2;
|
|
|
|
|
|
|
|
// Count how many bytes are to be pushed on the stack.
|
|
|
|
unsigned NumBytes = 0;
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
|
|
|
|
|
|
|
switch (Arg.getValueType()) {
|
|
|
|
default: assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::f32:
|
|
|
|
NumBytes += 4;
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
case MVT::f64:
|
|
|
|
NumBytes += 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
|
|
|
|
// Arguments go on the stack in reverse order, as specified by the ABI.
|
|
|
|
unsigned ArgOffset = 0;
|
|
|
|
std::vector<SDOperand> MemOpChains;
|
|
|
|
SDOperand StackPtr = DAG.getRegister(X86StackPtr, getPointerTy());
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
SDOperand Arg = Op.getOperand(5+2*i);
|
|
|
|
|
|
|
|
switch (Arg.getValueType()) {
|
|
|
|
default: assert(0 && "Unexpected ValueType for argument!");
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16: {
|
|
|
|
// Promote the integer to 32 bits. If the input type is signed use a
|
|
|
|
// sign extend, otherwise use a zero extend.
|
|
|
|
unsigned ExtOp =
|
|
|
|
dyn_cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue() ?
|
|
|
|
ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
|
|
|
|
Arg = DAG.getNode(ExtOp, MVT::i32, Arg);
|
|
|
|
}
|
|
|
|
// Fallthrough
|
|
|
|
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::f32: {
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
ArgOffset += 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MVT::i64:
|
|
|
|
case MVT::f64: {
|
|
|
|
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
|
|
|
|
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
|
|
|
|
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
|
|
|
Arg, PtrOff, DAG.getSrcValue(NULL)));
|
|
|
|
ArgOffset += 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!MemOpChains.empty())
|
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
|
|
|
|
&MemOpChains[0], MemOpChains.size());
|
|
|
|
|
|
|
|
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
|
|
|
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
|
|
|
|
else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
|
|
|
|
|
|
|
|
std::vector<MVT::ValueType> NodeTys;
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
|
|
|
|
|
|
|
Chain = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
|
|
|
|
NodeTys, &Ops[0], Ops.size());
|
|
|
|
SDOperand InFlag = Chain.getValue(1);
|
|
|
|
|
|
|
|
// Create the CALLSEQ_END node.
|
|
|
|
unsigned NumBytesForCalleeToPush;
|
|
|
|
|
|
|
|
if (isVarArg) {
|
|
|
|
NumBytesForCalleeToPush = 0;
|
|
|
|
} else {
|
|
|
|
NumBytesForCalleeToPush = NumBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
NodeTys.clear();
|
|
|
|
NodeTys.push_back(MVT::Other); // Returns a chain
|
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
|
|
|
|
Ops.push_back(DAG.getConstant(NumBytesForCalleeToPush, getPointerTy()));
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size());
|
|
|
|
if (RetVT != MVT::Other)
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
|
|
|
std::vector<SDOperand> ResultVals;
|
|
|
|
NodeTys.clear();
|
|
|
|
switch (RetVT) {
|
|
|
|
default: assert(0 && "Unknown value type to return!");
|
|
|
|
case MVT::Other: break;
|
|
|
|
case MVT::i8:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i8);
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i16);
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
if (Op.Val->getValueType(1) == MVT::i32) {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EDX, MVT::i32,
|
|
|
|
Chain.getValue(2)).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
NodeTys.push_back(MVT::i32);
|
|
|
|
} else {
|
|
|
|
Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
|
|
|
|
ResultVals.push_back(Chain.getValue(0));
|
|
|
|
}
|
|
|
|
NodeTys.push_back(MVT::i32);
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64: {
|
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::f64);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
SDOperand RetVal = DAG.getNode(X86ISD::FP_GET_RESULT, Tys,
|
|
|
|
&Ops[0], Ops.size());
|
|
|
|
Chain = RetVal.getValue(1);
|
|
|
|
InFlag = RetVal.getValue(2);
|
|
|
|
if (X86ScalarSSE) {
|
|
|
|
// FIXME: Currently the FST is flagged to the FP_GET_RESULT. This
|
|
|
|
// shouldn't be necessary except that RFP cannot be live across
|
|
|
|
// multiple blocks. When stackifier is fixed, they can be uncoupled.
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8);
|
|
|
|
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
|
|
|
|
Tys.clear();
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(RetVal);
|
|
|
|
Ops.push_back(StackSlot);
|
|
|
|
Ops.push_back(DAG.getValueType(RetVT));
|
|
|
|
Ops.push_back(InFlag);
|
|
|
|
Chain = DAG.getNode(X86ISD::FST, Tys, &Ops[0], Ops.size());
|
|
|
|
RetVal = DAG.getLoad(RetVT, Chain, StackSlot,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
Chain = RetVal.getValue(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RetVT == MVT::f32 && !X86ScalarSSE)
|
|
|
|
// FIXME: we would really like to remember that this FP_ROUND
|
|
|
|
// operation is okay to eliminate if we allow excess FP precision.
|
|
|
|
RetVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, RetVal);
|
|
|
|
ResultVals.push_back(RetVal);
|
|
|
|
NodeTys.push_back(RetVT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the function returns void, just return the chain.
|
|
|
|
if (ResultVals.empty())
|
|
|
|
return Chain;
|
|
|
|
|
|
|
|
// Otherwise, merge everything together with a MERGE_VALUES node.
|
|
|
|
NodeTys.push_back(MVT::Other);
|
|
|
|
ResultVals.push_back(Chain);
|
|
|
|
SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys,
|
|
|
|
&ResultVals[0], ResultVals.size());
|
|
|
|
return Res.getValue(Op.ResNo);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// FastCall Calling Convention implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The X86 'fastcall' calling convention passes up to two integer arguments in
|
|
|
|
// registers (an appropriate portion of ECX/EDX), passes arguments in C order,
|
|
|
|
// and requires that the callee pop its arguments off the stack (allowing proper
|
|
|
|
// tail calls), and has the same return value conventions as C calling convs.
|
|
|
|
//
|
|
|
|
// This calling convention always arranges for the callee pop value to be 8n+4
|
|
|
|
// bytes, which is needed for tail recursion elimination and stack alignment
|
|
|
|
// reasons.
|
|
|
|
//
|
|
|
|
|
|
|
|
/// HowToPassFastCallCCArgument - Returns how an formal argument of the
|
|
|
|
/// specified type should be passed. If it is through stack, returns the size of
|
|
|
|
/// the stack slot; if it is through integer register, returns the number of
|
|
|
|
/// integer registers are needed.
|
|
|
|
static void
|
|
|
|
HowToPassFastCallCCArgument(MVT::ValueType ObjectVT,
|
|
|
|
unsigned NumIntRegs,
|
|
|
|
unsigned &ObjSize,
|
|
|
|
unsigned &ObjIntRegs)
|
|
|
|
{
|
|
|
|
ObjSize = 0;
|
|
|
|
ObjIntRegs = 0;
|
|
|
|
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8:
|
|
|
|
if (NumIntRegs < 2)
|
|
|
|
ObjIntRegs = 1;
|
|
|
|
else
|
|
|
|
ObjSize = 1;
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
if (NumIntRegs < 2)
|
|
|
|
ObjIntRegs = 1;
|
|
|
|
else
|
|
|
|
ObjSize = 2;
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
if (NumIntRegs < 2)
|
|
|
|
ObjIntRegs = 1;
|
|
|
|
else
|
|
|
|
ObjSize = 4;
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
if (NumIntRegs+2 <= 2) {
|
|
|
|
ObjIntRegs = 2;
|
|
|
|
} else if (NumIntRegs+1 <= 2) {
|
|
|
|
ObjIntRegs = 1;
|
|
|
|
ObjSize = 4;
|
|
|
|
} else
|
|
|
|
ObjSize = 8;
|
|
|
|
case MVT::f32:
|
|
|
|
ObjSize = 4;
|
|
|
|
break;
|
|
|
|
case MVT::f64:
|
|
|
|
ObjSize = 8;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerFastCallCCArguments(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
unsigned NumArgs = Op.Val->getNumValues()-1;
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
|
|
SDOperand Root = Op.getOperand(0);
|
|
|
|
std::vector<SDOperand> ArgValues;
|
|
|
|
|
|
|
|
// Add DAG nodes to load the arguments... On entry to a function the stack
|
|
|
|
// frame looks like this:
|
|
|
|
//
|
|
|
|
// [ESP] -- return address
|
|
|
|
// [ESP + 4] -- first nonreg argument (leftmost lexically)
|
|
|
|
// [ESP + 8] -- second nonreg argument, if 1st argument is <= 4 bytes in size
|
|
|
|
// ...
|
|
|
|
unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
|
|
|
|
|
|
|
|
// Keep track of the number of integer regs passed so far. This can be either
|
|
|
|
// 0 (neither ECX or EDX used), 1 (ECX is used) or 2 (ECX and EDX are both
|
|
|
|
// used).
|
|
|
|
unsigned NumIntRegs = 0;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumArgs; ++i) {
|
|
|
|
MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
|
|
|
|
unsigned ArgIncrement = 4;
|
|
|
|
unsigned ObjSize = 0;
|
|
|
|
unsigned ObjIntRegs = 0;
|
|
|
|
|
|
|
|
HowToPassFastCallCCArgument(ObjectVT, NumIntRegs, ObjSize, ObjIntRegs);
|
|
|
|
if (ObjSize > 4)
|
|
|
|
ArgIncrement = ObjSize;
|
|
|
|
|
|
|
|
unsigned Reg = 0;
|
|
|
|
SDOperand ArgValue;
|
|
|
|
if (ObjIntRegs) {
|
|
|
|
switch (ObjectVT) {
|
|
|
|
default: assert(0 && "Unhandled argument type!");
|
|
|
|
case MVT::i8:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::DL : X86::CL,
|
|
|
|
X86::GR8RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i8);
|
|
|
|
break;
|
|
|
|
case MVT::i16:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::DX : X86::CX,
|
|
|
|
X86::GR16RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i16);
|
|
|
|
break;
|
|
|
|
case MVT::i32:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::ECX,
|
|
|
|
X86::GR32RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::ECX,
|
|
|
|
X86::GR32RegisterClass);
|
|
|
|
ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
|
|
|
|
if (ObjIntRegs == 2) {
|
|
|
|
Reg = AddLiveIn(MF, X86::EDX, X86::GR32RegisterClass);
|
|
|
|
SDOperand ArgValue2 = DAG.getCopyFromReg(Root, Reg, MVT::i32);
|
|
|
|
ArgValue= DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
NumIntRegs += ObjIntRegs;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ObjSize) {
|
|
|
|
// Create the SelectionDAG nodes corresponding to a load from this
|
|
|
|
// parameter.
|
|
|
|
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
|
|
|
|
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
|
|
|
|
if (ObjectVT == MVT::i64 && ObjIntRegs) {
|
|
|
|
SDOperand ArgValue2 = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
ArgValue = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
|
|
|
|
} else
|
|
|
|
ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
ArgOffset += ArgIncrement; // Move on to the next argument.
|
|
|
|
}
|
|
|
|
|
|
|
|
ArgValues.push_back(ArgValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
ArgValues.push_back(Root);
|
|
|
|
|
|
|
|
// Make sure the instruction takes 8n+4 bytes to make sure the start of the
|
|
|
|
// arguments and the arguments after the retaddr has been pushed are aligned.
|
|
|
|
if ((ArgOffset & 7) == 0)
|
|
|
|
ArgOffset += 4;
|
|
|
|
|
|
|
|
VarArgsFrameIndex = 0xAAAAAAA; // fastcc functions can't have varargs.
|
|
|
|
RegSaveFrameIndex = 0xAAAAAAA; // X86-64 only.
|
|
|
|
ReturnAddrIndex = 0; // No return address slot generated yet.
|
|
|
|
BytesToPopOnReturn = ArgOffset; // Callee pops all stack arguments.
|
|
|
|
BytesCallerReserves = 0;
|
|
|
|
|
|
|
|
MF.getInfo<X86FunctionInfo>()->setBytesToPopOnReturn(BytesToPopOnReturn);
|
|
|
|
|
|
|
|
// Finally, inform the code generator which regs we return values in.
|
|
|
|
switch (getValueType(MF.getFunction()->getReturnType())) {
|
|
|
|
default: assert(0 && "Unknown type!");
|
|
|
|
case MVT::isVoid: break;
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
MF.addLiveOut(X86::ECX);
|
|
|
|
break;
|
|
|
|
case MVT::i64:
|
|
|
|
MF.addLiveOut(X86::ECX);
|
|
|
|
MF.addLiveOut(X86::EDX);
|
|
|
|
break;
|
|
|
|
case MVT::f32:
|
|
|
|
case MVT::f64:
|
|
|
|
MF.addLiveOut(X86::ST0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the new list of results.
|
|
|
|
std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
|
|
|
|
Op.Val->value_end());
|
|
|
|
return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
|
|
|
|
}
|
|
|
|
|
2005-11-15 08:40:23 +08:00
|
|
|
SDOperand X86TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) {
|
|
|
|
if (ReturnAddrIndex == 0) {
|
|
|
|
// Set up a frame object for the return address.
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(8, -8);
|
|
|
|
else
|
|
|
|
ReturnAddrIndex = MF.getFrameInfo()->CreateFixedObject(4, -4);
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
return DAG.getFrameIndex(ReturnAddrIndex, getPointerTy());
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::pair<SDOperand, SDOperand> X86TargetLowering::
|
|
|
|
LowerFrameReturnAddress(bool isFrameAddress, SDOperand Chain, unsigned Depth,
|
|
|
|
SelectionDAG &DAG) {
|
|
|
|
SDOperand Result;
|
|
|
|
if (Depth) // Depths > 0 not supported yet!
|
|
|
|
Result = DAG.getConstant(0, getPointerTy());
|
|
|
|
else {
|
|
|
|
SDOperand RetAddrFI = getReturnAddressFrameIndex(DAG);
|
|
|
|
if (!isFrameAddress)
|
|
|
|
// Just load the return address
|
2006-09-08 14:48:29 +08:00
|
|
|
Result = DAG.getLoad(getPointerTy(), DAG.getEntryNode(), RetAddrFI,
|
2005-11-15 08:40:23 +08:00
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
else
|
2006-09-08 14:48:29 +08:00
|
|
|
Result = DAG.getNode(ISD::SUB, getPointerTy(), RetAddrFI,
|
|
|
|
DAG.getConstant(4, getPointerTy()));
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
return std::make_pair(Result, Chain);
|
|
|
|
}
|
|
|
|
|
2006-01-11 08:33:36 +08:00
|
|
|
/// getCondBrOpcodeForX86CC - Returns the X86 conditional branch opcode
|
|
|
|
/// which corresponds to the condition code.
|
|
|
|
static unsigned getCondBrOpcodeForX86CC(unsigned X86CC) {
|
|
|
|
switch (X86CC) {
|
|
|
|
default: assert(0 && "Unknown X86 conditional code!");
|
|
|
|
case X86ISD::COND_A: return X86::JA;
|
|
|
|
case X86ISD::COND_AE: return X86::JAE;
|
|
|
|
case X86ISD::COND_B: return X86::JB;
|
|
|
|
case X86ISD::COND_BE: return X86::JBE;
|
|
|
|
case X86ISD::COND_E: return X86::JE;
|
|
|
|
case X86ISD::COND_G: return X86::JG;
|
|
|
|
case X86ISD::COND_GE: return X86::JGE;
|
|
|
|
case X86ISD::COND_L: return X86::JL;
|
|
|
|
case X86ISD::COND_LE: return X86::JLE;
|
|
|
|
case X86ISD::COND_NE: return X86::JNE;
|
|
|
|
case X86ISD::COND_NO: return X86::JNO;
|
|
|
|
case X86ISD::COND_NP: return X86::JNP;
|
|
|
|
case X86ISD::COND_NS: return X86::JNS;
|
|
|
|
case X86ISD::COND_O: return X86::JO;
|
|
|
|
case X86ISD::COND_P: return X86::JP;
|
|
|
|
case X86ISD::COND_S: return X86::JS;
|
|
|
|
}
|
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
|
2006-01-31 07:41:35 +08:00
|
|
|
/// translateX86CC - do a one to one translation of a ISD::CondCode to the X86
|
|
|
|
/// specific condition code. It returns a false if it cannot do a direct
|
2006-09-13 11:22:10 +08:00
|
|
|
/// translation. X86CC is the translated CondCode. LHS/RHS are modified as
|
|
|
|
/// needed.
|
2006-04-06 07:38:46 +08:00
|
|
|
static bool translateX86CC(ISD::CondCode SetCCOpcode, bool isFP,
|
2006-09-13 11:22:10 +08:00
|
|
|
unsigned &X86CC, SDOperand &LHS, SDOperand &RHS,
|
|
|
|
SelectionDAG &DAG) {
|
2006-01-31 07:41:35 +08:00
|
|
|
X86CC = X86ISD::COND_INVALID;
|
2006-01-06 08:43:03 +08:00
|
|
|
if (!isFP) {
|
2006-09-14 01:04:54 +08:00
|
|
|
if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
|
|
|
|
if (SetCCOpcode == ISD::SETGT && RHSC->isAllOnesValue()) {
|
|
|
|
// X > -1 -> X == 0, jump !sign.
|
|
|
|
RHS = DAG.getConstant(0, RHS.getValueType());
|
|
|
|
X86CC = X86ISD::COND_NS;
|
|
|
|
return true;
|
|
|
|
} else if (SetCCOpcode == ISD::SETLT && RHSC->isNullValue()) {
|
|
|
|
// X < 0 -> X == 0, jump on sign.
|
|
|
|
X86CC = X86ISD::COND_S;
|
|
|
|
return true;
|
|
|
|
}
|
2006-09-13 11:22:10 +08:00
|
|
|
}
|
|
|
|
|
2006-01-06 08:43:03 +08:00
|
|
|
switch (SetCCOpcode) {
|
|
|
|
default: break;
|
|
|
|
case ISD::SETEQ: X86CC = X86ISD::COND_E; break;
|
|
|
|
case ISD::SETGT: X86CC = X86ISD::COND_G; break;
|
|
|
|
case ISD::SETGE: X86CC = X86ISD::COND_GE; break;
|
|
|
|
case ISD::SETLT: X86CC = X86ISD::COND_L; break;
|
|
|
|
case ISD::SETLE: X86CC = X86ISD::COND_LE; break;
|
|
|
|
case ISD::SETNE: X86CC = X86ISD::COND_NE; break;
|
|
|
|
case ISD::SETULT: X86CC = X86ISD::COND_B; break;
|
|
|
|
case ISD::SETUGT: X86CC = X86ISD::COND_A; break;
|
|
|
|
case ISD::SETULE: X86CC = X86ISD::COND_BE; break;
|
|
|
|
case ISD::SETUGE: X86CC = X86ISD::COND_AE; break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// On a floating point condition, the flags are set as follows:
|
|
|
|
// ZF PF CF op
|
|
|
|
// 0 | 0 | 0 | X > Y
|
|
|
|
// 0 | 0 | 1 | X < Y
|
|
|
|
// 1 | 0 | 0 | X == Y
|
|
|
|
// 1 | 1 | 1 | unordered
|
2006-09-13 11:22:10 +08:00
|
|
|
bool Flip = false;
|
2006-01-06 08:43:03 +08:00
|
|
|
switch (SetCCOpcode) {
|
|
|
|
default: break;
|
|
|
|
case ISD::SETUEQ:
|
|
|
|
case ISD::SETEQ: X86CC = X86ISD::COND_E; break;
|
2006-04-17 15:24:10 +08:00
|
|
|
case ISD::SETOLT: Flip = true; // Fallthrough
|
2006-01-06 08:43:03 +08:00
|
|
|
case ISD::SETOGT:
|
|
|
|
case ISD::SETGT: X86CC = X86ISD::COND_A; break;
|
2006-04-17 15:24:10 +08:00
|
|
|
case ISD::SETOLE: Flip = true; // Fallthrough
|
2006-01-06 08:43:03 +08:00
|
|
|
case ISD::SETOGE:
|
|
|
|
case ISD::SETGE: X86CC = X86ISD::COND_AE; break;
|
2006-04-17 15:24:10 +08:00
|
|
|
case ISD::SETUGT: Flip = true; // Fallthrough
|
2006-01-06 08:43:03 +08:00
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETLT: X86CC = X86ISD::COND_B; break;
|
2006-04-17 15:24:10 +08:00
|
|
|
case ISD::SETUGE: Flip = true; // Fallthrough
|
2006-01-06 08:43:03 +08:00
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETLE: X86CC = X86ISD::COND_BE; break;
|
|
|
|
case ISD::SETONE:
|
|
|
|
case ISD::SETNE: X86CC = X86ISD::COND_NE; break;
|
|
|
|
case ISD::SETUO: X86CC = X86ISD::COND_P; break;
|
|
|
|
case ISD::SETO: X86CC = X86ISD::COND_NP; break;
|
|
|
|
}
|
2006-09-13 11:22:10 +08:00
|
|
|
if (Flip)
|
|
|
|
std::swap(LHS, RHS);
|
2006-01-06 08:43:03 +08:00
|
|
|
}
|
2006-01-31 07:41:35 +08:00
|
|
|
|
|
|
|
return X86CC != X86ISD::COND_INVALID;
|
2006-01-06 08:43:03 +08:00
|
|
|
}
|
|
|
|
|
2006-01-11 08:33:36 +08:00
|
|
|
/// hasFPCMov - is there a floating point cmov for the specific X86 condition
|
|
|
|
/// code. Current x86 isa includes the following FP cmov instructions:
|
2006-01-11 04:26:56 +08:00
|
|
|
/// fcmovb, fcomvbe, fcomve, fcmovu, fcmovae, fcmova, fcmovne, fcmovnu.
|
2006-01-11 08:33:36 +08:00
|
|
|
static bool hasFPCMov(unsigned X86CC) {
|
2006-01-11 04:26:56 +08:00
|
|
|
switch (X86CC) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case X86ISD::COND_B:
|
|
|
|
case X86ISD::COND_BE:
|
|
|
|
case X86ISD::COND_E:
|
|
|
|
case X86ISD::COND_P:
|
|
|
|
case X86ISD::COND_A:
|
|
|
|
case X86ISD::COND_AE:
|
|
|
|
case X86ISD::COND_NE:
|
|
|
|
case X86ISD::COND_NP:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-03-14 07:18:16 +08:00
|
|
|
/// DarwinGVRequiresExtraLoad - true if accessing the GV requires an extra
|
|
|
|
/// load. For Darwin, external and weak symbols are indirect, loading the value
|
|
|
|
/// at address GV rather then the value of GV itself. This means that the
|
|
|
|
/// GlobalAddress must be in the base or index register of the address, not the
|
|
|
|
/// GV offset field.
|
|
|
|
static bool DarwinGVRequiresExtraLoad(GlobalValue *GV) {
|
|
|
|
return (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
|
|
|
|
(GV->isExternal() && !GV->hasNotBeenReadFromBytecode()));
|
|
|
|
}
|
|
|
|
|
2006-09-17 21:06:18 +08:00
|
|
|
/// WindowsGVRequiresExtraLoad - true if accessing the GV requires an extra
|
2006-09-21 06:03:51 +08:00
|
|
|
/// load. For Windows, dllimported symbols are indirect, loading the value at
|
|
|
|
/// address GV rather then the value of GV itself. This means that the
|
|
|
|
/// GlobalAddress must be in the base or index register of the address, not the
|
|
|
|
/// GV offset field.
|
2006-09-15 02:23:27 +08:00
|
|
|
static bool WindowsGVRequiresExtraLoad(GlobalValue *GV) {
|
2006-09-17 21:06:18 +08:00
|
|
|
return (GV->hasDLLImportLinkage());
|
2006-09-15 02:23:27 +08:00
|
|
|
}
|
|
|
|
|
2006-04-07 07:23:56 +08:00
|
|
|
/// isUndefOrInRange - Op is either an undef node or a ConstantSDNode. Return
|
2006-04-08 05:53:05 +08:00
|
|
|
/// true if Op is undef or if its value falls within the specified range (L, H].
|
2006-04-07 07:23:56 +08:00
|
|
|
static bool isUndefOrInRange(SDOperand Op, unsigned Low, unsigned Hi) {
|
|
|
|
if (Op.getOpcode() == ISD::UNDEF)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Op)->getValue();
|
2006-04-08 05:53:05 +08:00
|
|
|
return (Val >= Low && Val < Hi);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isUndefOrEqual - Op is either an undef node or a ConstantSDNode. Return
|
|
|
|
/// true if Op is undef or if its value equal to the specified value.
|
|
|
|
static bool isUndefOrEqual(SDOperand Op, unsigned Val) {
|
|
|
|
if (Op.getOpcode() == ISD::UNDEF)
|
|
|
|
return true;
|
|
|
|
return cast<ConstantSDNode>(Op)->getValue() == Val;
|
2006-04-07 07:23:56 +08:00
|
|
|
}
|
|
|
|
|
2006-03-23 02:59:22 +08:00
|
|
|
/// isPSHUFDMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to PSHUFD.
|
|
|
|
bool X86::isPSHUFDMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
if (N->getNumOperands() != 4)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check if the value doesn't reference the second vector.
|
2006-03-30 07:07:14 +08:00
|
|
|
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
|
2006-03-31 08:30:29 +08:00
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
if (cast<ConstantSDNode>(Arg)->getValue() >= 4)
|
2006-03-30 07:07:14 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isPSHUFHWMask - Return true if the specified VECTOR_SHUFFLE operand
|
2006-04-05 09:47:37 +08:00
|
|
|
/// specifies a shuffle of elements that is suitable for input to PSHUFHW.
|
2006-03-30 07:07:14 +08:00
|
|
|
bool X86::isPSHUFHWMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
if (N->getNumOperands() != 8)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Lower quadword copied in order.
|
|
|
|
for (unsigned i = 0; i != 4; ++i) {
|
2006-03-31 08:30:29 +08:00
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
if (cast<ConstantSDNode>(Arg)->getValue() != i)
|
2006-03-30 07:07:14 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upper quadword shuffled.
|
|
|
|
for (unsigned i = 4; i != 8; ++i) {
|
2006-03-31 08:30:29 +08:00
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
2006-03-30 07:07:14 +08:00
|
|
|
if (Val < 4 || Val > 7)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isPSHUFLWMask - Return true if the specified VECTOR_SHUFFLE operand
|
2006-04-05 09:47:37 +08:00
|
|
|
/// specifies a shuffle of elements that is suitable for input to PSHUFLW.
|
2006-03-30 07:07:14 +08:00
|
|
|
bool X86::isPSHUFLWMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
if (N->getNumOperands() != 8)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Upper quadword copied in order.
|
2006-04-08 05:53:05 +08:00
|
|
|
for (unsigned i = 4; i != 8; ++i)
|
|
|
|
if (!isUndefOrEqual(N->getOperand(i), i))
|
2006-03-30 07:07:14 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Lower quadword shuffled.
|
2006-04-08 05:53:05 +08:00
|
|
|
for (unsigned i = 0; i != 4; ++i)
|
|
|
|
if (!isUndefOrInRange(N->getOperand(i), 0, 4))
|
2006-03-30 07:07:14 +08:00
|
|
|
return false;
|
2006-03-24 09:18:28 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isSHUFPMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to SHUFP*.
|
2006-04-20 16:58:49 +08:00
|
|
|
static bool isSHUFPMask(std::vector<SDOperand> &N) {
|
|
|
|
unsigned NumElems = N.size();
|
|
|
|
if (NumElems != 2 && NumElems != 4) return false;
|
2006-03-24 09:18:28 +08:00
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
unsigned Half = NumElems / 2;
|
|
|
|
for (unsigned i = 0; i < Half; ++i)
|
|
|
|
if (!isUndefOrInRange(N[i], 0, NumElems))
|
|
|
|
return false;
|
|
|
|
for (unsigned i = Half; i < NumElems; ++i)
|
|
|
|
if (!isUndefOrInRange(N[i], NumElems, NumElems*2))
|
|
|
|
return false;
|
2006-03-24 10:58:06 +08:00
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
return true;
|
|
|
|
}
|
2006-03-24 09:18:28 +08:00
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
bool X86::isSHUFPMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
|
|
|
return ::isSHUFPMask(Ops);
|
|
|
|
}
|
2006-03-23 02:59:22 +08:00
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
/// isCommutedSHUFP - Returns true if the shuffle mask is except
|
|
|
|
/// the reverse of what x86 shuffles want. x86 shuffles requires the lower
|
|
|
|
/// half elements to come from vector 1 (which would equal the dest.) and
|
|
|
|
/// the upper half to come from vector 2.
|
|
|
|
static bool isCommutedSHUFP(std::vector<SDOperand> &Ops) {
|
|
|
|
unsigned NumElems = Ops.size();
|
|
|
|
if (NumElems != 2 && NumElems != 4) return false;
|
|
|
|
|
|
|
|
unsigned Half = NumElems / 2;
|
|
|
|
for (unsigned i = 0; i < Half; ++i)
|
|
|
|
if (!isUndefOrInRange(Ops[i], NumElems, NumElems*2))
|
|
|
|
return false;
|
|
|
|
for (unsigned i = Half; i < NumElems; ++i)
|
|
|
|
if (!isUndefOrInRange(Ops[i], 0, NumElems))
|
|
|
|
return false;
|
2006-03-23 02:59:22 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
static bool isCommutedSHUFP(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
|
|
|
return isCommutedSHUFP(Ops);
|
|
|
|
}
|
|
|
|
|
2006-03-24 10:58:06 +08:00
|
|
|
/// isMOVHLPSMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to MOVHLPS.
|
|
|
|
bool X86::isMOVHLPSMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
2006-03-28 14:50:32 +08:00
|
|
|
if (N->getNumOperands() != 4)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Expect bit0 == 6, bit1 == 7, bit2 == 2, bit3 == 3
|
2006-04-08 05:53:05 +08:00
|
|
|
return isUndefOrEqual(N->getOperand(0), 6) &&
|
|
|
|
isUndefOrEqual(N->getOperand(1), 7) &&
|
|
|
|
isUndefOrEqual(N->getOperand(2), 2) &&
|
|
|
|
isUndefOrEqual(N->getOperand(3), 3);
|
2006-03-28 14:50:32 +08:00
|
|
|
}
|
|
|
|
|
2006-04-07 07:23:56 +08:00
|
|
|
/// isMOVLPMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to MOVLP{S|D}.
|
|
|
|
bool X86::isMOVLPMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
unsigned NumElems = N->getNumOperands();
|
|
|
|
if (NumElems != 2 && NumElems != 4)
|
|
|
|
return false;
|
|
|
|
|
2006-04-08 05:53:05 +08:00
|
|
|
for (unsigned i = 0; i < NumElems/2; ++i)
|
|
|
|
if (!isUndefOrEqual(N->getOperand(i), i + NumElems))
|
|
|
|
return false;
|
2006-04-07 07:23:56 +08:00
|
|
|
|
2006-04-08 05:53:05 +08:00
|
|
|
for (unsigned i = NumElems/2; i < NumElems; ++i)
|
|
|
|
if (!isUndefOrEqual(N->getOperand(i), i))
|
|
|
|
return false;
|
2006-04-07 07:23:56 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isMOVHPMask - Return true if the specified VECTOR_SHUFFLE operand
|
2006-04-20 04:35:22 +08:00
|
|
|
/// specifies a shuffle of elements that is suitable for input to MOVHP{S|D}
|
|
|
|
/// and MOVLHPS.
|
2006-04-07 07:23:56 +08:00
|
|
|
bool X86::isMOVHPMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
unsigned NumElems = N->getNumOperands();
|
|
|
|
if (NumElems != 2 && NumElems != 4)
|
|
|
|
return false;
|
|
|
|
|
2006-04-08 05:53:05 +08:00
|
|
|
for (unsigned i = 0; i < NumElems/2; ++i)
|
|
|
|
if (!isUndefOrEqual(N->getOperand(i), i))
|
|
|
|
return false;
|
2006-04-07 07:23:56 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumElems/2; ++i) {
|
|
|
|
SDOperand Arg = N->getOperand(i + NumElems/2);
|
2006-04-08 05:53:05 +08:00
|
|
|
if (!isUndefOrEqual(Arg, i + NumElems))
|
|
|
|
return false;
|
2006-04-07 07:23:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-03-28 10:43:26 +08:00
|
|
|
/// isUNPCKLMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to UNPCKL.
|
2006-04-20 16:58:49 +08:00
|
|
|
bool static isUNPCKLMask(std::vector<SDOperand> &N, bool V2IsSplat = false) {
|
|
|
|
unsigned NumElems = N.size();
|
2006-03-28 10:43:26 +08:00
|
|
|
if (NumElems != 2 && NumElems != 4 && NumElems != 8 && NumElems != 16)
|
2006-03-24 10:58:06 +08:00
|
|
|
return false;
|
|
|
|
|
2006-03-28 10:43:26 +08:00
|
|
|
for (unsigned i = 0, j = 0; i != NumElems; i += 2, ++j) {
|
2006-04-20 16:58:49 +08:00
|
|
|
SDOperand BitI = N[i];
|
|
|
|
SDOperand BitI1 = N[i+1];
|
2006-04-08 05:53:05 +08:00
|
|
|
if (!isUndefOrEqual(BitI, j))
|
|
|
|
return false;
|
2006-04-20 16:58:49 +08:00
|
|
|
if (V2IsSplat) {
|
|
|
|
if (isUndefOrEqual(BitI1, NumElems))
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (!isUndefOrEqual(BitI1, j + NumElems))
|
|
|
|
return false;
|
|
|
|
}
|
2006-03-28 10:43:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2006-03-24 10:58:06 +08:00
|
|
|
}
|
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
bool X86::isUNPCKLMask(SDNode *N, bool V2IsSplat) {
|
2006-03-28 08:39:58 +08:00
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
2006-04-20 16:58:49 +08:00
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
|
|
|
return ::isUNPCKLMask(Ops, V2IsSplat);
|
|
|
|
}
|
2006-03-28 08:39:58 +08:00
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
/// isUNPCKHMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to UNPCKH.
|
|
|
|
bool static isUNPCKHMask(std::vector<SDOperand> &N, bool V2IsSplat = false) {
|
|
|
|
unsigned NumElems = N.size();
|
2006-03-28 08:39:58 +08:00
|
|
|
if (NumElems != 2 && NumElems != 4 && NumElems != 8 && NumElems != 16)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (unsigned i = 0, j = 0; i != NumElems; i += 2, ++j) {
|
2006-04-20 16:58:49 +08:00
|
|
|
SDOperand BitI = N[i];
|
|
|
|
SDOperand BitI1 = N[i+1];
|
2006-04-08 05:53:05 +08:00
|
|
|
if (!isUndefOrEqual(BitI, j + NumElems/2))
|
|
|
|
return false;
|
2006-04-20 16:58:49 +08:00
|
|
|
if (V2IsSplat) {
|
|
|
|
if (isUndefOrEqual(BitI1, NumElems))
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (!isUndefOrEqual(BitI1, j + NumElems/2 + NumElems))
|
|
|
|
return false;
|
|
|
|
}
|
2006-03-28 08:39:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
bool X86::isUNPCKHMask(SDNode *N, bool V2IsSplat) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
|
|
|
return ::isUNPCKHMask(Ops, V2IsSplat);
|
|
|
|
}
|
|
|
|
|
Handle canonical form of e.g.
vector_shuffle v1, v1, <0, 4, 1, 5, 2, 6, 3, 7>
This is turned into
vector_shuffle v1, <undef>, <0, 0, 1, 1, 2, 2, 3, 3>
by dag combiner.
It would match a {p}unpckl on x86.
llvm-svn: 27437
2006-04-05 15:20:06 +08:00
|
|
|
/// isUNPCKL_v_undef_Mask - Special case of isUNPCKLMask for canonical form
|
|
|
|
/// of vector_shuffle v, v, <0, 4, 1, 5>, i.e. vector_shuffle v, undef,
|
|
|
|
/// <0, 0, 1, 1>
|
|
|
|
bool X86::isUNPCKL_v_undef_Mask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
unsigned NumElems = N->getNumOperands();
|
|
|
|
if (NumElems != 4 && NumElems != 8 && NumElems != 16)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (unsigned i = 0, j = 0; i != NumElems; i += 2, ++j) {
|
|
|
|
SDOperand BitI = N->getOperand(i);
|
|
|
|
SDOperand BitI1 = N->getOperand(i+1);
|
|
|
|
|
2006-04-08 05:53:05 +08:00
|
|
|
if (!isUndefOrEqual(BitI, j))
|
|
|
|
return false;
|
|
|
|
if (!isUndefOrEqual(BitI1, j))
|
|
|
|
return false;
|
Handle canonical form of e.g.
vector_shuffle v1, v1, <0, 4, 1, 5, 2, 6, 3, 7>
This is turned into
vector_shuffle v1, <undef>, <0, 0, 1, 1, 2, 2, 3, 3>
by dag combiner.
It would match a {p}unpckl on x86.
llvm-svn: 27437
2006-04-05 15:20:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
/// isMOVLMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to MOVSS,
|
|
|
|
/// MOVSD, and MOVD, i.e. setting the lowest element.
|
|
|
|
static bool isMOVLMask(std::vector<SDOperand> &N) {
|
2006-04-20 16:58:49 +08:00
|
|
|
unsigned NumElems = N.size();
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
if (NumElems != 2 && NumElems != 4 && NumElems != 8 && NumElems != 16)
|
2006-04-20 16:58:49 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!isUndefOrEqual(N[0], NumElems))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (unsigned i = 1; i < NumElems; ++i) {
|
|
|
|
SDOperand Arg = N[i];
|
|
|
|
if (!isUndefOrEqual(Arg, i))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
bool X86::isMOVLMask(SDNode *N) {
|
2006-04-11 08:19:04 +08:00
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
2006-04-20 16:58:49 +08:00
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
return ::isMOVLMask(Ops);
|
2006-04-20 16:58:49 +08:00
|
|
|
}
|
2006-04-11 08:19:04 +08:00
|
|
|
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
/// isCommutedMOVL - Returns true if the shuffle mask is except the reverse
|
|
|
|
/// of what x86 movss want. X86 movs requires the lowest element to be lowest
|
2006-04-20 16:58:49 +08:00
|
|
|
/// element of vector 2 and the other elements to come from vector 1 in order.
|
2006-09-08 09:50:06 +08:00
|
|
|
static bool isCommutedMOVL(std::vector<SDOperand> &Ops, bool V2IsSplat = false,
|
|
|
|
bool V2IsUndef = false) {
|
2006-04-20 16:58:49 +08:00
|
|
|
unsigned NumElems = Ops.size();
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
if (NumElems != 2 && NumElems != 4 && NumElems != 8 && NumElems != 16)
|
2006-04-11 08:19:04 +08:00
|
|
|
return false;
|
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
if (!isUndefOrEqual(Ops[0], 0))
|
2006-04-11 08:19:04 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
for (unsigned i = 1; i < NumElems; ++i) {
|
2006-04-20 16:58:49 +08:00
|
|
|
SDOperand Arg = Ops[i];
|
2006-09-08 09:50:06 +08:00
|
|
|
if (!(isUndefOrEqual(Arg, i+NumElems) ||
|
|
|
|
(V2IsUndef && isUndefOrInRange(Arg, NumElems, NumElems*2)) ||
|
|
|
|
(V2IsSplat && isUndefOrEqual(Arg, NumElems))))
|
|
|
|
return false;
|
2006-04-11 08:19:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
Handle canonical form of e.g.
vector_shuffle v1, v1, <0, 4, 1, 5, 2, 6, 3, 7>
This is turned into
vector_shuffle v1, <undef>, <0, 0, 1, 1, 2, 2, 3, 3>
by dag combiner.
It would match a {p}unpckl on x86.
llvm-svn: 27437
2006-04-05 15:20:06 +08:00
|
|
|
|
2006-09-08 09:50:06 +08:00
|
|
|
static bool isCommutedMOVL(SDNode *N, bool V2IsSplat = false,
|
|
|
|
bool V2IsUndef = false) {
|
2006-04-20 16:58:49 +08:00
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
2006-09-08 09:50:06 +08:00
|
|
|
return isCommutedMOVL(Ops, V2IsSplat, V2IsUndef);
|
2006-04-20 16:58:49 +08:00
|
|
|
}
|
|
|
|
|
2006-04-15 05:59:03 +08:00
|
|
|
/// isMOVSHDUPMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to MOVSHDUP.
|
|
|
|
bool X86::isMOVSHDUPMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
if (N->getNumOperands() != 4)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Expect 1, 1, 3, 3
|
|
|
|
for (unsigned i = 0; i < 2; ++i) {
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val != 1) return false;
|
|
|
|
}
|
2006-04-15 13:37:34 +08:00
|
|
|
|
|
|
|
bool HasHi = false;
|
2006-04-15 05:59:03 +08:00
|
|
|
for (unsigned i = 2; i < 4; ++i) {
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val != 3) return false;
|
2006-04-15 13:37:34 +08:00
|
|
|
HasHi = true;
|
2006-04-15 05:59:03 +08:00
|
|
|
}
|
2006-04-15 11:13:24 +08:00
|
|
|
|
2006-04-15 13:37:34 +08:00
|
|
|
// Don't use movshdup if it can be done with a shufps.
|
|
|
|
return HasHi;
|
2006-04-15 05:59:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// isMOVSLDUPMask - Return true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a shuffle of elements that is suitable for input to MOVSLDUP.
|
|
|
|
bool X86::isMOVSLDUPMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
if (N->getNumOperands() != 4)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Expect 0, 0, 2, 2
|
|
|
|
for (unsigned i = 0; i < 2; ++i) {
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val != 0) return false;
|
|
|
|
}
|
2006-04-15 13:37:34 +08:00
|
|
|
|
|
|
|
bool HasHi = false;
|
2006-04-15 05:59:03 +08:00
|
|
|
for (unsigned i = 2; i < 4; ++i) {
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val != 2) return false;
|
2006-04-15 13:37:34 +08:00
|
|
|
HasHi = true;
|
2006-04-15 05:59:03 +08:00
|
|
|
}
|
2006-04-15 11:13:24 +08:00
|
|
|
|
2006-04-15 13:37:34 +08:00
|
|
|
// Don't use movshdup if it can be done with a shufps.
|
|
|
|
return HasHi;
|
2006-04-15 05:59:03 +08:00
|
|
|
}
|
|
|
|
|
2006-03-22 10:53:00 +08:00
|
|
|
/// isSplatMask - Return true if the specified VECTOR_SHUFFLE operand specifies
|
|
|
|
/// a splat of a single element.
|
2006-04-18 04:43:08 +08:00
|
|
|
static bool isSplatMask(SDNode *N) {
|
2006-03-22 10:53:00 +08:00
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
// This is a splat operation if each element of the permute is the same, and
|
|
|
|
// if the value doesn't reference the second vector.
|
2006-04-20 07:28:59 +08:00
|
|
|
unsigned NumElems = N->getNumOperands();
|
|
|
|
SDOperand ElementBase;
|
|
|
|
unsigned i = 0;
|
|
|
|
for (; i != NumElems; ++i) {
|
|
|
|
SDOperand Elt = N->getOperand(i);
|
|
|
|
if (ConstantSDNode *EltV = dyn_cast<ConstantSDNode>(Elt)) {
|
|
|
|
ElementBase = Elt;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ElementBase.Val)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (; i != NumElems; ++i) {
|
2006-03-31 08:30:29 +08:00
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
2006-04-20 07:28:59 +08:00
|
|
|
if (Arg != ElementBase) return false;
|
2006-03-22 10:53:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure it is a splat of the first vector operand.
|
2006-04-20 07:28:59 +08:00
|
|
|
return cast<ConstantSDNode>(ElementBase)->getValue() < NumElems;
|
2006-03-22 10:53:00 +08:00
|
|
|
}
|
|
|
|
|
2006-04-18 04:43:08 +08:00
|
|
|
/// isSplatMask - Return true if the specified VECTOR_SHUFFLE operand specifies
|
|
|
|
/// a splat of a single element and it's a 2 or 4 element mask.
|
|
|
|
bool X86::isSplatMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
2006-04-20 07:28:59 +08:00
|
|
|
// We can only splat 64-bit, and 32-bit quantities with a single instruction.
|
2006-04-18 04:43:08 +08:00
|
|
|
if (N->getNumOperands() != 4 && N->getNumOperands() != 2)
|
|
|
|
return false;
|
|
|
|
return ::isSplatMask(N);
|
|
|
|
}
|
|
|
|
|
2006-03-22 16:01:21 +08:00
|
|
|
/// getShuffleSHUFImmediate - Return the appropriate immediate to shuffle
|
|
|
|
/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUF* and SHUFP*
|
|
|
|
/// instructions.
|
|
|
|
unsigned X86::getShuffleSHUFImmediate(SDNode *N) {
|
2006-03-22 10:53:00 +08:00
|
|
|
unsigned NumOperands = N->getNumOperands();
|
|
|
|
unsigned Shift = (NumOperands == 4) ? 2 : 1;
|
|
|
|
unsigned Mask = 0;
|
2006-03-29 07:41:33 +08:00
|
|
|
for (unsigned i = 0; i < NumOperands; ++i) {
|
2006-03-31 08:30:29 +08:00
|
|
|
unsigned Val = 0;
|
|
|
|
SDOperand Arg = N->getOperand(NumOperands-i-1);
|
|
|
|
if (Arg.getOpcode() != ISD::UNDEF)
|
|
|
|
Val = cast<ConstantSDNode>(Arg)->getValue();
|
2006-03-24 09:18:28 +08:00
|
|
|
if (Val >= NumOperands) Val -= NumOperands;
|
2006-03-22 16:01:21 +08:00
|
|
|
Mask |= Val;
|
2006-03-29 07:41:33 +08:00
|
|
|
if (i != NumOperands - 1)
|
|
|
|
Mask <<= Shift;
|
|
|
|
}
|
2006-03-22 16:01:21 +08:00
|
|
|
|
|
|
|
return Mask;
|
|
|
|
}
|
|
|
|
|
2006-03-30 07:07:14 +08:00
|
|
|
/// getShufflePSHUFHWImmediate - Return the appropriate immediate to shuffle
|
|
|
|
/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFHW
|
|
|
|
/// instructions.
|
|
|
|
unsigned X86::getShufflePSHUFHWImmediate(SDNode *N) {
|
|
|
|
unsigned Mask = 0;
|
|
|
|
// 8 nodes, but we only care about the last 4.
|
|
|
|
for (unsigned i = 7; i >= 4; --i) {
|
2006-03-31 08:30:29 +08:00
|
|
|
unsigned Val = 0;
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() != ISD::UNDEF)
|
|
|
|
Val = cast<ConstantSDNode>(Arg)->getValue();
|
2006-03-30 07:07:14 +08:00
|
|
|
Mask |= (Val - 4);
|
|
|
|
if (i != 4)
|
|
|
|
Mask <<= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getShufflePSHUFLWImmediate - Return the appropriate immediate to shuffle
|
|
|
|
/// the specified isShuffleMask VECTOR_SHUFFLE mask with PSHUFLW
|
|
|
|
/// instructions.
|
|
|
|
unsigned X86::getShufflePSHUFLWImmediate(SDNode *N) {
|
|
|
|
unsigned Mask = 0;
|
|
|
|
// 8 nodes, but we only care about the first 4.
|
|
|
|
for (int i = 3; i >= 0; --i) {
|
2006-03-31 08:30:29 +08:00
|
|
|
unsigned Val = 0;
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() != ISD::UNDEF)
|
|
|
|
Val = cast<ConstantSDNode>(Arg)->getValue();
|
2006-03-30 07:07:14 +08:00
|
|
|
Mask |= Val;
|
|
|
|
if (i != 0)
|
|
|
|
Mask <<= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Mask;
|
|
|
|
}
|
|
|
|
|
2006-04-05 09:47:37 +08:00
|
|
|
/// isPSHUFHW_PSHUFLWMask - true if the specified VECTOR_SHUFFLE operand
|
|
|
|
/// specifies a 8 element shuffle that can be broken into a pair of
|
|
|
|
/// PSHUFHW and PSHUFLW.
|
|
|
|
static bool isPSHUFHW_PSHUFLWMask(SDNode *N) {
|
|
|
|
assert(N->getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
if (N->getNumOperands() != 8)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Lower quadword shuffled.
|
|
|
|
for (unsigned i = 0; i != 4; ++i) {
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val > 4)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upper quadword shuffled.
|
|
|
|
for (unsigned i = 4; i != 8; ++i) {
|
|
|
|
SDOperand Arg = N->getOperand(i);
|
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) continue;
|
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val < 4 || Val > 7)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-07 07:23:56 +08:00
|
|
|
/// CommuteVectorShuffle - Swap vector_shuffle operandsas well as
|
|
|
|
/// values in ther permute mask.
|
|
|
|
static SDOperand CommuteVectorShuffle(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand V1 = Op.getOperand(0);
|
|
|
|
SDOperand V2 = Op.getOperand(1);
|
|
|
|
SDOperand Mask = Op.getOperand(2);
|
|
|
|
MVT::ValueType VT = Op.getValueType();
|
|
|
|
MVT::ValueType MaskVT = Mask.getValueType();
|
|
|
|
MVT::ValueType EltVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
unsigned NumElems = Mask.getNumOperands();
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i != NumElems; ++i) {
|
|
|
|
SDOperand Arg = Mask.getOperand(i);
|
2006-04-20 06:48:17 +08:00
|
|
|
if (Arg.getOpcode() == ISD::UNDEF) {
|
|
|
|
MaskVec.push_back(DAG.getNode(ISD::UNDEF, EltVT));
|
|
|
|
continue;
|
|
|
|
}
|
2006-04-07 07:23:56 +08:00
|
|
|
assert(isa<ConstantSDNode>(Arg) && "Invalid VECTOR_SHUFFLE mask!");
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val < NumElems)
|
|
|
|
MaskVec.push_back(DAG.getConstant(Val + NumElems, EltVT));
|
|
|
|
else
|
|
|
|
MaskVec.push_back(DAG.getConstant(Val - NumElems, EltVT));
|
|
|
|
}
|
|
|
|
|
2006-08-08 10:23:42 +08:00
|
|
|
Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT, &MaskVec[0], MaskVec.size());
|
2006-04-07 07:23:56 +08:00
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V2, V1, Mask);
|
|
|
|
}
|
|
|
|
|
2006-04-20 04:35:22 +08:00
|
|
|
/// ShouldXformToMOVHLPS - Return true if the node should be transformed to
|
|
|
|
/// match movhlps. The lower half elements should come from upper half of
|
|
|
|
/// V1 (and in order), and the upper half elements should come from the upper
|
|
|
|
/// half of V2 (and in order).
|
|
|
|
static bool ShouldXformToMOVHLPS(SDNode *Mask) {
|
|
|
|
unsigned NumElems = Mask->getNumOperands();
|
|
|
|
if (NumElems != 4)
|
|
|
|
return false;
|
|
|
|
for (unsigned i = 0, e = 2; i != e; ++i)
|
|
|
|
if (!isUndefOrEqual(Mask->getOperand(i), i+2))
|
|
|
|
return false;
|
|
|
|
for (unsigned i = 2; i != 4; ++i)
|
|
|
|
if (!isUndefOrEqual(Mask->getOperand(i), i+4))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-07 07:23:56 +08:00
|
|
|
/// isScalarLoadToVector - Returns true if the node is a scalar load that
|
|
|
|
/// is promoted to a vector.
|
2006-04-20 04:35:22 +08:00
|
|
|
static inline bool isScalarLoadToVector(SDNode *N) {
|
|
|
|
if (N->getOpcode() == ISD::SCALAR_TO_VECTOR) {
|
|
|
|
N = N->getOperand(0).Val;
|
|
|
|
return (N->getOpcode() == ISD::LOAD);
|
2006-04-07 07:23:56 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-04-20 04:35:22 +08:00
|
|
|
/// ShouldXformToMOVLP{S|D} - Return true if the node should be transformed to
|
|
|
|
/// match movlp{s|d}. The lower half elements should come from lower half of
|
|
|
|
/// V1 (and in order), and the upper half elements should come from the upper
|
|
|
|
/// half of V2 (and in order). And since V1 will become the source of the
|
|
|
|
/// MOVLP, it must be either a vector load or a scalar load to vector.
|
|
|
|
static bool ShouldXformToMOVLP(SDNode *V1, SDNode *Mask) {
|
|
|
|
if (V1->getOpcode() != ISD::LOAD && !isScalarLoadToVector(V1))
|
|
|
|
return false;
|
2006-04-07 07:23:56 +08:00
|
|
|
|
2006-04-20 04:35:22 +08:00
|
|
|
unsigned NumElems = Mask->getNumOperands();
|
|
|
|
if (NumElems != 2 && NumElems != 4)
|
|
|
|
return false;
|
|
|
|
for (unsigned i = 0, e = NumElems/2; i != e; ++i)
|
|
|
|
if (!isUndefOrEqual(Mask->getOperand(i), i))
|
|
|
|
return false;
|
|
|
|
for (unsigned i = NumElems/2; i != NumElems; ++i)
|
|
|
|
if (!isUndefOrEqual(Mask->getOperand(i), i+NumElems))
|
|
|
|
return false;
|
|
|
|
return true;
|
2006-04-07 07:23:56 +08:00
|
|
|
}
|
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
/// isSplatVector - Returns true if N is a BUILD_VECTOR node whose elements are
|
|
|
|
/// all the same.
|
|
|
|
static bool isSplatVector(SDNode *N) {
|
|
|
|
if (N->getOpcode() != ISD::BUILD_VECTOR)
|
|
|
|
return false;
|
2006-04-07 07:23:56 +08:00
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
SDOperand SplatValue = N->getOperand(0);
|
|
|
|
for (unsigned i = 1, e = N->getNumOperands(); i != e; ++i)
|
|
|
|
if (N->getOperand(i) != SplatValue)
|
2006-04-07 07:23:56 +08:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-09-08 09:50:06 +08:00
|
|
|
/// isUndefShuffle - Returns true if N is a VECTOR_SHUFFLE that can be resolved
|
|
|
|
/// to an undef.
|
|
|
|
static bool isUndefShuffle(SDNode *N) {
|
|
|
|
if (N->getOpcode() != ISD::BUILD_VECTOR)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SDOperand V1 = N->getOperand(0);
|
|
|
|
SDOperand V2 = N->getOperand(1);
|
|
|
|
SDOperand Mask = N->getOperand(2);
|
|
|
|
unsigned NumElems = Mask.getNumOperands();
|
|
|
|
for (unsigned i = 0; i != NumElems; ++i) {
|
|
|
|
SDOperand Arg = Mask.getOperand(i);
|
|
|
|
if (Arg.getOpcode() != ISD::UNDEF) {
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val < NumElems && V1.getOpcode() != ISD::UNDEF)
|
|
|
|
return false;
|
|
|
|
else if (Val >= NumElems && V2.getOpcode() != ISD::UNDEF)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
/// NormalizeMask - V2 is a splat, modify the mask (if needed) so all elements
|
|
|
|
/// that point to V2 points to its first element.
|
|
|
|
static SDOperand NormalizeMask(SDOperand Mask, SelectionDAG &DAG) {
|
|
|
|
assert(Mask.getOpcode() == ISD::BUILD_VECTOR);
|
|
|
|
|
|
|
|
bool Changed = false;
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
unsigned NumElems = Mask.getNumOperands();
|
|
|
|
for (unsigned i = 0; i != NumElems; ++i) {
|
|
|
|
SDOperand Arg = Mask.getOperand(i);
|
|
|
|
if (Arg.getOpcode() != ISD::UNDEF) {
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Arg)->getValue();
|
|
|
|
if (Val > NumElems) {
|
|
|
|
Arg = DAG.getConstant(NumElems, Arg.getValueType());
|
|
|
|
Changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MaskVec.push_back(Arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Changed)
|
2006-08-08 10:23:42 +08:00
|
|
|
Mask = DAG.getNode(ISD::BUILD_VECTOR, Mask.getValueType(),
|
|
|
|
&MaskVec[0], MaskVec.size());
|
2006-04-20 16:58:49 +08:00
|
|
|
return Mask;
|
|
|
|
}
|
|
|
|
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
/// getMOVLMask - Returns a vector_shuffle mask for an movs{s|d}, movd
|
|
|
|
/// operation of specified width.
|
|
|
|
static SDOperand getMOVLMask(unsigned NumElems, SelectionDAG &DAG) {
|
2006-04-20 16:58:49 +08:00
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
|
|
|
|
MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
MaskVec.push_back(DAG.getConstant(NumElems, BaseVT));
|
|
|
|
for (unsigned i = 1; i != NumElems; ++i)
|
|
|
|
MaskVec.push_back(DAG.getConstant(i, BaseVT));
|
2006-08-08 10:23:42 +08:00
|
|
|
return DAG.getNode(ISD::BUILD_VECTOR, MaskVT, &MaskVec[0], MaskVec.size());
|
2006-04-20 16:58:49 +08:00
|
|
|
}
|
|
|
|
|
2006-04-18 04:43:08 +08:00
|
|
|
/// getUnpacklMask - Returns a vector_shuffle mask for an unpackl operation
|
|
|
|
/// of specified width.
|
|
|
|
static SDOperand getUnpacklMask(unsigned NumElems, SelectionDAG &DAG) {
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
|
|
|
|
MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
for (unsigned i = 0, e = NumElems/2; i != e; ++i) {
|
|
|
|
MaskVec.push_back(DAG.getConstant(i, BaseVT));
|
|
|
|
MaskVec.push_back(DAG.getConstant(i + NumElems, BaseVT));
|
|
|
|
}
|
2006-08-08 10:23:42 +08:00
|
|
|
return DAG.getNode(ISD::BUILD_VECTOR, MaskVT, &MaskVec[0], MaskVec.size());
|
2006-04-18 04:43:08 +08:00
|
|
|
}
|
|
|
|
|
2006-04-20 16:58:49 +08:00
|
|
|
/// getUnpackhMask - Returns a vector_shuffle mask for an unpackh operation
|
|
|
|
/// of specified width.
|
|
|
|
static SDOperand getUnpackhMask(unsigned NumElems, SelectionDAG &DAG) {
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
|
|
|
|
MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
unsigned Half = NumElems/2;
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
for (unsigned i = 0; i != Half; ++i) {
|
|
|
|
MaskVec.push_back(DAG.getConstant(i + Half, BaseVT));
|
|
|
|
MaskVec.push_back(DAG.getConstant(i + NumElems + Half, BaseVT));
|
|
|
|
}
|
2006-08-08 10:23:42 +08:00
|
|
|
return DAG.getNode(ISD::BUILD_VECTOR, MaskVT, &MaskVec[0], MaskVec.size());
|
2006-04-20 16:58:49 +08:00
|
|
|
}
|
|
|
|
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
/// getZeroVector - Returns a vector of specified type with all zero elements.
|
|
|
|
///
|
|
|
|
static SDOperand getZeroVector(MVT::ValueType VT, SelectionDAG &DAG) {
|
|
|
|
assert(MVT::isVector(VT) && "Expected a vector type");
|
|
|
|
unsigned NumElems = getVectorNumElements(VT);
|
|
|
|
MVT::ValueType EVT = MVT::getVectorBaseType(VT);
|
|
|
|
bool isFP = MVT::isFloatingPoint(EVT);
|
|
|
|
SDOperand Zero = isFP ? DAG.getConstantFP(0.0, EVT) : DAG.getConstant(0, EVT);
|
|
|
|
std::vector<SDOperand> ZeroVec(NumElems, Zero);
|
2006-08-08 10:23:42 +08:00
|
|
|
return DAG.getNode(ISD::BUILD_VECTOR, VT, &ZeroVec[0], ZeroVec.size());
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
}
|
|
|
|
|
2006-04-18 04:43:08 +08:00
|
|
|
/// PromoteSplat - Promote a splat of v8i16 or v16i8 to v4i32.
|
|
|
|
///
|
|
|
|
static SDOperand PromoteSplat(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand V1 = Op.getOperand(0);
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
SDOperand Mask = Op.getOperand(2);
|
2006-04-18 04:43:08 +08:00
|
|
|
MVT::ValueType VT = Op.getValueType();
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
unsigned NumElems = Mask.getNumOperands();
|
|
|
|
Mask = getUnpacklMask(NumElems, DAG);
|
2006-04-18 04:43:08 +08:00
|
|
|
while (NumElems != 4) {
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
V1 = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V1, Mask);
|
2006-04-18 04:43:08 +08:00
|
|
|
NumElems >>= 1;
|
|
|
|
}
|
|
|
|
V1 = DAG.getNode(ISD::BIT_CONVERT, MVT::v4i32, V1);
|
|
|
|
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
Mask = getZeroVector(MaskVT, DAG);
|
2006-04-18 04:43:08 +08:00
|
|
|
SDOperand Shuffle = DAG.getNode(ISD::VECTOR_SHUFFLE, MVT::v4i32, V1,
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
DAG.getNode(ISD::UNDEF, MVT::v4i32), Mask);
|
2006-04-18 04:43:08 +08:00
|
|
|
return DAG.getNode(ISD::BIT_CONVERT, VT, Shuffle);
|
|
|
|
}
|
|
|
|
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
/// isZeroNode - Returns true if Elt is a constant zero or a floating point
|
|
|
|
/// constant +0.0.
|
|
|
|
static inline bool isZeroNode(SDOperand Elt) {
|
|
|
|
return ((isa<ConstantSDNode>(Elt) &&
|
|
|
|
cast<ConstantSDNode>(Elt)->getValue() == 0) ||
|
|
|
|
(isa<ConstantFPSDNode>(Elt) &&
|
|
|
|
cast<ConstantFPSDNode>(Elt)->isExactlyValue(0.0)));
|
|
|
|
}
|
|
|
|
|
Revamp build_vector lowering to take advantage of movss and movd instructions.
movd always clear the top 96 bits and movss does so when it's loading the
value from memory.
The net result is codegen for 4-wide shuffles is much improved. It is near
optimal if one or more elements is a zero. e.g.
__m128i test(int a, int b) {
return _mm_set_epi32(0, 0, b, a);
}
compiles to
_test:
movd 8(%esp), %xmm1
movd 4(%esp), %xmm0
punpckldq %xmm1, %xmm0
ret
compare to gcc:
_test:
subl $12, %esp
movd 20(%esp), %xmm0
movd 16(%esp), %xmm1
punpckldq %xmm0, %xmm1
movq %xmm1, %xmm0
movhps LC0, %xmm0
addl $12, %esp
ret
or icc:
_test:
movd 4(%esp), %xmm0 #5.10
movd 8(%esp), %xmm3 #5.10
xorl %eax, %eax #5.10
movd %eax, %xmm1 #5.10
punpckldq %xmm1, %xmm0 #5.10
movd %eax, %xmm2 #5.10
punpckldq %xmm2, %xmm3 #5.10
punpckldq %xmm3, %xmm0 #5.10
ret #5.10
There are still room for improvement, for example the FP variant of the above example:
__m128 test(float a, float b) {
return _mm_set_ps(0.0, 0.0, b, a);
}
_test:
movss 8(%esp), %xmm1
movss 4(%esp), %xmm0
unpcklps %xmm1, %xmm0
xorps %xmm1, %xmm1
movlhps %xmm1, %xmm0
ret
The xorps and movlhps are unnecessary. This will require post legalizer optimization to handle.
llvm-svn: 27939
2006-04-22 07:03:30 +08:00
|
|
|
/// getShuffleVectorZeroOrUndef - Return a vector_shuffle of the specified
|
|
|
|
/// vector and zero or undef vector.
|
|
|
|
static SDOperand getShuffleVectorZeroOrUndef(SDOperand V2, MVT::ValueType VT,
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
unsigned NumElems, unsigned Idx,
|
Revamp build_vector lowering to take advantage of movss and movd instructions.
movd always clear the top 96 bits and movss does so when it's loading the
value from memory.
The net result is codegen for 4-wide shuffles is much improved. It is near
optimal if one or more elements is a zero. e.g.
__m128i test(int a, int b) {
return _mm_set_epi32(0, 0, b, a);
}
compiles to
_test:
movd 8(%esp), %xmm1
movd 4(%esp), %xmm0
punpckldq %xmm1, %xmm0
ret
compare to gcc:
_test:
subl $12, %esp
movd 20(%esp), %xmm0
movd 16(%esp), %xmm1
punpckldq %xmm0, %xmm1
movq %xmm1, %xmm0
movhps LC0, %xmm0
addl $12, %esp
ret
or icc:
_test:
movd 4(%esp), %xmm0 #5.10
movd 8(%esp), %xmm3 #5.10
xorl %eax, %eax #5.10
movd %eax, %xmm1 #5.10
punpckldq %xmm1, %xmm0 #5.10
movd %eax, %xmm2 #5.10
punpckldq %xmm2, %xmm3 #5.10
punpckldq %xmm3, %xmm0 #5.10
ret #5.10
There are still room for improvement, for example the FP variant of the above example:
__m128 test(float a, float b) {
return _mm_set_ps(0.0, 0.0, b, a);
}
_test:
movss 8(%esp), %xmm1
movss 4(%esp), %xmm0
unpcklps %xmm1, %xmm0
xorps %xmm1, %xmm1
movlhps %xmm1, %xmm0
ret
The xorps and movlhps are unnecessary. This will require post legalizer optimization to handle.
llvm-svn: 27939
2006-04-22 07:03:30 +08:00
|
|
|
bool isZero, SelectionDAG &DAG) {
|
|
|
|
SDOperand V1 = isZero ? getZeroVector(VT, DAG) : DAG.getNode(ISD::UNDEF, VT);
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
|
|
|
|
MVT::ValueType EVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
SDOperand Zero = DAG.getConstant(0, EVT);
|
|
|
|
std::vector<SDOperand> MaskVec(NumElems, Zero);
|
|
|
|
MaskVec[Idx] = DAG.getConstant(NumElems, EVT);
|
2006-08-08 10:23:42 +08:00
|
|
|
SDOperand Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&MaskVec[0], MaskVec.size());
|
Revamp build_vector lowering to take advantage of movss and movd instructions.
movd always clear the top 96 bits and movss does so when it's loading the
value from memory.
The net result is codegen for 4-wide shuffles is much improved. It is near
optimal if one or more elements is a zero. e.g.
__m128i test(int a, int b) {
return _mm_set_epi32(0, 0, b, a);
}
compiles to
_test:
movd 8(%esp), %xmm1
movd 4(%esp), %xmm0
punpckldq %xmm1, %xmm0
ret
compare to gcc:
_test:
subl $12, %esp
movd 20(%esp), %xmm0
movd 16(%esp), %xmm1
punpckldq %xmm0, %xmm1
movq %xmm1, %xmm0
movhps LC0, %xmm0
addl $12, %esp
ret
or icc:
_test:
movd 4(%esp), %xmm0 #5.10
movd 8(%esp), %xmm3 #5.10
xorl %eax, %eax #5.10
movd %eax, %xmm1 #5.10
punpckldq %xmm1, %xmm0 #5.10
movd %eax, %xmm2 #5.10
punpckldq %xmm2, %xmm3 #5.10
punpckldq %xmm3, %xmm0 #5.10
ret #5.10
There are still room for improvement, for example the FP variant of the above example:
__m128 test(float a, float b) {
return _mm_set_ps(0.0, 0.0, b, a);
}
_test:
movss 8(%esp), %xmm1
movss 4(%esp), %xmm0
unpcklps %xmm1, %xmm0
xorps %xmm1, %xmm1
movlhps %xmm1, %xmm0
ret
The xorps and movlhps are unnecessary. This will require post legalizer optimization to handle.
llvm-svn: 27939
2006-04-22 07:03:30 +08:00
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask);
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
}
|
|
|
|
|
2006-04-25 02:01:45 +08:00
|
|
|
/// LowerBuildVectorv16i8 - Custom lower build_vector of v16i8.
|
|
|
|
///
|
|
|
|
static SDOperand LowerBuildVectorv16i8(SDOperand Op, unsigned NonZeros,
|
|
|
|
unsigned NumNonZero, unsigned NumZero,
|
2006-09-08 14:48:29 +08:00
|
|
|
SelectionDAG &DAG, TargetLowering &TLI) {
|
2006-04-25 02:01:45 +08:00
|
|
|
if (NumNonZero > 8)
|
|
|
|
return SDOperand();
|
|
|
|
|
|
|
|
SDOperand V(0, 0);
|
|
|
|
bool First = true;
|
|
|
|
for (unsigned i = 0; i < 16; ++i) {
|
|
|
|
bool ThisIsNonZero = (NonZeros & (1 << i)) != 0;
|
|
|
|
if (ThisIsNonZero && First) {
|
|
|
|
if (NumZero)
|
|
|
|
V = getZeroVector(MVT::v8i16, DAG);
|
|
|
|
else
|
|
|
|
V = DAG.getNode(ISD::UNDEF, MVT::v8i16);
|
|
|
|
First = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((i & 1) != 0) {
|
|
|
|
SDOperand ThisElt(0, 0), LastElt(0, 0);
|
|
|
|
bool LastIsNonZero = (NonZeros & (1 << (i-1))) != 0;
|
|
|
|
if (LastIsNonZero) {
|
|
|
|
LastElt = DAG.getNode(ISD::ZERO_EXTEND, MVT::i16, Op.getOperand(i-1));
|
|
|
|
}
|
|
|
|
if (ThisIsNonZero) {
|
|
|
|
ThisElt = DAG.getNode(ISD::ZERO_EXTEND, MVT::i16, Op.getOperand(i));
|
|
|
|
ThisElt = DAG.getNode(ISD::SHL, MVT::i16,
|
|
|
|
ThisElt, DAG.getConstant(8, MVT::i8));
|
|
|
|
if (LastIsNonZero)
|
|
|
|
ThisElt = DAG.getNode(ISD::OR, MVT::i16, ThisElt, LastElt);
|
|
|
|
} else
|
|
|
|
ThisElt = LastElt;
|
|
|
|
|
|
|
|
if (ThisElt.Val)
|
|
|
|
V = DAG.getNode(ISD::INSERT_VECTOR_ELT, MVT::v8i16, V, ThisElt,
|
2006-09-08 14:48:29 +08:00
|
|
|
DAG.getConstant(i/2, TLI.getPointerTy()));
|
2006-04-25 02:01:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DAG.getNode(ISD::BIT_CONVERT, MVT::v16i8, V);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LowerBuildVectorv16i8 - Custom lower build_vector of v8i16.
|
|
|
|
///
|
|
|
|
static SDOperand LowerBuildVectorv8i16(SDOperand Op, unsigned NonZeros,
|
|
|
|
unsigned NumNonZero, unsigned NumZero,
|
2006-09-08 14:48:29 +08:00
|
|
|
SelectionDAG &DAG, TargetLowering &TLI) {
|
2006-04-25 02:01:45 +08:00
|
|
|
if (NumNonZero > 4)
|
|
|
|
return SDOperand();
|
|
|
|
|
|
|
|
SDOperand V(0, 0);
|
|
|
|
bool First = true;
|
|
|
|
for (unsigned i = 0; i < 8; ++i) {
|
|
|
|
bool isNonZero = (NonZeros & (1 << i)) != 0;
|
|
|
|
if (isNonZero) {
|
|
|
|
if (First) {
|
|
|
|
if (NumZero)
|
|
|
|
V = getZeroVector(MVT::v8i16, DAG);
|
|
|
|
else
|
|
|
|
V = DAG.getNode(ISD::UNDEF, MVT::v8i16);
|
|
|
|
First = false;
|
|
|
|
}
|
|
|
|
V = DAG.getNode(ISD::INSERT_VECTOR_ELT, MVT::v8i16, V, Op.getOperand(i),
|
2006-09-08 14:48:29 +08:00
|
|
|
DAG.getConstant(i, TLI.getPointerTy()));
|
2006-04-25 02:01:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerBUILD_VECTOR(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
// All zero's are handled with pxor.
|
|
|
|
if (ISD::isBuildVectorAllZeros(Op.Val))
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
// All one's are handled with pcmpeqd.
|
|
|
|
if (ISD::isBuildVectorAllOnes(Op.Val))
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
MVT::ValueType VT = Op.getValueType();
|
|
|
|
MVT::ValueType EVT = MVT::getVectorBaseType(VT);
|
|
|
|
unsigned EVTBits = MVT::getSizeInBits(EVT);
|
|
|
|
|
|
|
|
unsigned NumElems = Op.getNumOperands();
|
|
|
|
unsigned NumZero = 0;
|
|
|
|
unsigned NumNonZero = 0;
|
|
|
|
unsigned NonZeros = 0;
|
|
|
|
std::set<SDOperand> Values;
|
|
|
|
for (unsigned i = 0; i < NumElems; ++i) {
|
|
|
|
SDOperand Elt = Op.getOperand(i);
|
|
|
|
if (Elt.getOpcode() != ISD::UNDEF) {
|
|
|
|
Values.insert(Elt);
|
|
|
|
if (isZeroNode(Elt))
|
|
|
|
NumZero++;
|
|
|
|
else {
|
|
|
|
NonZeros |= (1 << i);
|
|
|
|
NumNonZero++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NumNonZero == 0)
|
|
|
|
// Must be a mix of zero and undef. Return a zero vector.
|
|
|
|
return getZeroVector(VT, DAG);
|
|
|
|
|
|
|
|
// Splat is obviously ok. Let legalizer expand it to a shuffle.
|
|
|
|
if (Values.size() == 1)
|
|
|
|
return SDOperand();
|
|
|
|
|
|
|
|
// Special case for single non-zero element.
|
|
|
|
if (NumNonZero == 1) {
|
|
|
|
unsigned Idx = CountTrailingZeros_32(NonZeros);
|
|
|
|
SDOperand Item = Op.getOperand(Idx);
|
|
|
|
Item = DAG.getNode(ISD::SCALAR_TO_VECTOR, VT, Item);
|
|
|
|
if (Idx == 0)
|
|
|
|
// Turn it into a MOVL (i.e. movss, movsd, or movd) to a zero vector.
|
|
|
|
return getShuffleVectorZeroOrUndef(Item, VT, NumElems, Idx,
|
|
|
|
NumZero > 0, DAG);
|
|
|
|
|
|
|
|
if (EVTBits == 32) {
|
|
|
|
// Turn it into a shuffle of zero and zero-extended scalar to vector.
|
|
|
|
Item = getShuffleVectorZeroOrUndef(Item, VT, NumElems, 0, NumZero > 0,
|
|
|
|
DAG);
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
|
|
|
|
MVT::ValueType MaskEVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
for (unsigned i = 0; i < NumElems; i++)
|
|
|
|
MaskVec.push_back(DAG.getConstant((i == Idx) ? 0 : 1, MaskEVT));
|
2006-08-08 10:23:42 +08:00
|
|
|
SDOperand Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&MaskVec[0], MaskVec.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, Item,
|
|
|
|
DAG.getNode(ISD::UNDEF, VT), Mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let legalizer expand 2-widde build_vector's.
|
|
|
|
if (EVTBits == 64)
|
|
|
|
return SDOperand();
|
|
|
|
|
|
|
|
// If element VT is < 32 bits, convert it to inserts into a zero vector.
|
|
|
|
if (EVTBits == 8) {
|
2006-09-08 14:48:29 +08:00
|
|
|
SDOperand V = LowerBuildVectorv16i8(Op, NonZeros,NumNonZero,NumZero, DAG,
|
|
|
|
*this);
|
2006-04-26 04:13:52 +08:00
|
|
|
if (V.Val) return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EVTBits == 16) {
|
2006-09-08 14:48:29 +08:00
|
|
|
SDOperand V = LowerBuildVectorv8i16(Op, NonZeros,NumNonZero,NumZero, DAG,
|
|
|
|
*this);
|
2006-04-26 04:13:52 +08:00
|
|
|
if (V.Val) return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If element VT is == 32 bits, turn it into a number of shuffles.
|
|
|
|
std::vector<SDOperand> V(NumElems);
|
|
|
|
if (NumElems == 4 && NumZero > 0) {
|
|
|
|
for (unsigned i = 0; i < 4; ++i) {
|
|
|
|
bool isZero = !(NonZeros & (1 << i));
|
|
|
|
if (isZero)
|
|
|
|
V[i] = getZeroVector(VT, DAG);
|
|
|
|
else
|
|
|
|
V[i] = DAG.getNode(ISD::SCALAR_TO_VECTOR, VT, Op.getOperand(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < 2; ++i) {
|
|
|
|
switch ((NonZeros & (0x3 << i*2)) >> (i*2)) {
|
|
|
|
default: break;
|
|
|
|
case 0:
|
|
|
|
V[i] = V[i*2]; // Must be a zero vector.
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
V[i] = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V[i*2+1], V[i*2],
|
|
|
|
getMOVLMask(NumElems, DAG));
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
V[i] = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V[i*2], V[i*2+1],
|
|
|
|
getMOVLMask(NumElems, DAG));
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
V[i] = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V[i*2], V[i*2+1],
|
|
|
|
getUnpacklMask(NumElems, DAG));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-16 15:21:53 +08:00
|
|
|
// Take advantage of the fact GR32 to VR128 scalar_to_vector (i.e. movd)
|
2006-04-26 04:13:52 +08:00
|
|
|
// clears the upper bits.
|
|
|
|
// FIXME: we can do the same for v4f32 case when we know both parts of
|
|
|
|
// the lower half come from scalar_to_vector (loadf32). We should do
|
|
|
|
// that in post legalizer dag combiner with target specific hooks.
|
|
|
|
if (MVT::isInteger(EVT) && (NonZeros & (0x3 << 2)) == 0)
|
|
|
|
return V[0];
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
|
|
|
|
MVT::ValueType EVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
bool Reverse = (NonZeros & 0x3) == 2;
|
|
|
|
for (unsigned i = 0; i < 2; ++i)
|
|
|
|
if (Reverse)
|
|
|
|
MaskVec.push_back(DAG.getConstant(1-i, EVT));
|
|
|
|
else
|
|
|
|
MaskVec.push_back(DAG.getConstant(i, EVT));
|
|
|
|
Reverse = ((NonZeros & (0x3 << 2)) >> 2) == 2;
|
|
|
|
for (unsigned i = 0; i < 2; ++i)
|
|
|
|
if (Reverse)
|
|
|
|
MaskVec.push_back(DAG.getConstant(1-i+NumElems, EVT));
|
|
|
|
else
|
|
|
|
MaskVec.push_back(DAG.getConstant(i+NumElems, EVT));
|
2006-08-12 01:38:39 +08:00
|
|
|
SDOperand ShufMask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&MaskVec[0], MaskVec.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V[0], V[1], ShufMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Values.size() > 2) {
|
|
|
|
// Expand into a number of unpckl*.
|
|
|
|
// e.g. for v4f32
|
|
|
|
// Step 1: unpcklps 0, 2 ==> X: <?, ?, 2, 0>
|
|
|
|
// : unpcklps 1, 3 ==> Y: <?, ?, 3, 1>
|
|
|
|
// Step 2: unpcklps X, Y ==> <3, 2, 1, 0>
|
|
|
|
SDOperand UnpckMask = getUnpacklMask(NumElems, DAG);
|
|
|
|
for (unsigned i = 0; i < NumElems; ++i)
|
|
|
|
V[i] = DAG.getNode(ISD::SCALAR_TO_VECTOR, VT, Op.getOperand(i));
|
|
|
|
NumElems >>= 1;
|
|
|
|
while (NumElems != 0) {
|
|
|
|
for (unsigned i = 0; i < NumElems; ++i)
|
|
|
|
V[i] = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V[i], V[i + NumElems],
|
|
|
|
UnpckMask);
|
|
|
|
NumElems >>= 1;
|
|
|
|
}
|
|
|
|
return V[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
return SDOperand();
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerVECTOR_SHUFFLE(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand V1 = Op.getOperand(0);
|
|
|
|
SDOperand V2 = Op.getOperand(1);
|
|
|
|
SDOperand PermMask = Op.getOperand(2);
|
|
|
|
MVT::ValueType VT = Op.getValueType();
|
|
|
|
unsigned NumElems = PermMask.getNumOperands();
|
|
|
|
bool V1IsUndef = V1.getOpcode() == ISD::UNDEF;
|
|
|
|
bool V2IsUndef = V2.getOpcode() == ISD::UNDEF;
|
|
|
|
|
2006-09-08 09:50:06 +08:00
|
|
|
if (isUndefShuffle(Op.Val))
|
|
|
|
return DAG.getNode(ISD::UNDEF, VT);
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
if (isSplatMask(PermMask.Val)) {
|
|
|
|
if (NumElems <= 4) return Op;
|
|
|
|
// Promote it to a v4i32 splat.
|
|
|
|
return PromoteSplat(Op, DAG);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (X86::isMOVLMask(PermMask.Val))
|
|
|
|
return (V1IsUndef) ? V2 : Op;
|
|
|
|
|
|
|
|
if (X86::isMOVSHDUPMask(PermMask.Val) ||
|
|
|
|
X86::isMOVSLDUPMask(PermMask.Val) ||
|
|
|
|
X86::isMOVHLPSMask(PermMask.Val) ||
|
|
|
|
X86::isMOVHPMask(PermMask.Val) ||
|
|
|
|
X86::isMOVLPMask(PermMask.Val))
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
if (ShouldXformToMOVHLPS(PermMask.Val) ||
|
|
|
|
ShouldXformToMOVLP(V1.Val, PermMask.Val))
|
|
|
|
return CommuteVectorShuffle(Op, DAG);
|
|
|
|
|
2006-09-08 09:50:06 +08:00
|
|
|
bool V1IsSplat = isSplatVector(V1.Val);
|
|
|
|
bool V2IsSplat = isSplatVector(V2.Val);
|
|
|
|
if ((V1IsSplat || V1IsUndef) && !(V2IsSplat || V2IsUndef)) {
|
2006-04-26 04:13:52 +08:00
|
|
|
Op = CommuteVectorShuffle(Op, DAG);
|
|
|
|
V1 = Op.getOperand(0);
|
|
|
|
V2 = Op.getOperand(1);
|
|
|
|
PermMask = Op.getOperand(2);
|
2006-09-08 09:50:06 +08:00
|
|
|
std::swap(V1IsSplat, V2IsSplat);
|
|
|
|
std::swap(V1IsUndef, V2IsUndef);
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
2006-09-08 09:50:06 +08:00
|
|
|
if (isCommutedMOVL(PermMask.Val, V2IsSplat, V2IsUndef)) {
|
2006-04-26 04:13:52 +08:00
|
|
|
if (V2IsUndef) return V1;
|
|
|
|
Op = CommuteVectorShuffle(Op, DAG);
|
|
|
|
V1 = Op.getOperand(0);
|
|
|
|
V2 = Op.getOperand(1);
|
|
|
|
PermMask = Op.getOperand(2);
|
|
|
|
if (V2IsSplat) {
|
|
|
|
// V2 is a splat, so the mask may be malformed. That is, it may point
|
|
|
|
// to any V2 element. The instruction selectior won't like this. Get
|
|
|
|
// a corrected mask and commute to form a proper MOVS{S|D}.
|
|
|
|
SDOperand NewMask = getMOVLMask(NumElems, DAG);
|
|
|
|
if (NewMask.Val != PermMask.Val)
|
|
|
|
Op = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, NewMask);
|
|
|
|
}
|
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (X86::isUNPCKL_v_undef_Mask(PermMask.Val) ||
|
|
|
|
X86::isUNPCKLMask(PermMask.Val) ||
|
|
|
|
X86::isUNPCKHMask(PermMask.Val))
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
if (V2IsSplat) {
|
|
|
|
// Normalize mask so all entries that point to V2 points to its first
|
|
|
|
// element then try to match unpck{h|l} again. If match, return a
|
|
|
|
// new vector_shuffle with the corrected mask.
|
|
|
|
SDOperand NewMask = NormalizeMask(PermMask, DAG);
|
|
|
|
if (NewMask.Val != PermMask.Val) {
|
|
|
|
if (X86::isUNPCKLMask(PermMask.Val, true)) {
|
|
|
|
SDOperand NewMask = getUnpacklMask(NumElems, DAG);
|
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, NewMask);
|
|
|
|
} else if (X86::isUNPCKHMask(PermMask.Val, true)) {
|
|
|
|
SDOperand NewMask = getUnpackhMask(NumElems, DAG);
|
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, NewMask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Normalize the node to match x86 shuffle ops if needed
|
|
|
|
if (V2.getOpcode() != ISD::UNDEF)
|
|
|
|
if (isCommutedSHUFP(PermMask.Val)) {
|
|
|
|
Op = CommuteVectorShuffle(Op, DAG);
|
|
|
|
V1 = Op.getOperand(0);
|
|
|
|
V2 = Op.getOperand(1);
|
|
|
|
PermMask = Op.getOperand(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If VT is integer, try PSHUF* first, then SHUFP*.
|
|
|
|
if (MVT::isInteger(VT)) {
|
|
|
|
if (X86::isPSHUFDMask(PermMask.Val) ||
|
|
|
|
X86::isPSHUFHWMask(PermMask.Val) ||
|
|
|
|
X86::isPSHUFLWMask(PermMask.Val)) {
|
|
|
|
if (V2.getOpcode() != ISD::UNDEF)
|
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1,
|
|
|
|
DAG.getNode(ISD::UNDEF, V1.getValueType()),PermMask);
|
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (X86::isSHUFPMask(PermMask.Val))
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
// Handle v8i16 shuffle high / low shuffle node pair.
|
|
|
|
if (VT == MVT::v8i16 && isPSHUFHW_PSHUFLWMask(PermMask.Val)) {
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(NumElems);
|
|
|
|
MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
for (unsigned i = 0; i != 4; ++i)
|
|
|
|
MaskVec.push_back(PermMask.getOperand(i));
|
|
|
|
for (unsigned i = 4; i != 8; ++i)
|
|
|
|
MaskVec.push_back(DAG.getConstant(i, BaseVT));
|
2006-08-12 01:38:39 +08:00
|
|
|
SDOperand Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&MaskVec[0], MaskVec.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
V1 = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask);
|
|
|
|
MaskVec.clear();
|
|
|
|
for (unsigned i = 0; i != 4; ++i)
|
|
|
|
MaskVec.push_back(DAG.getConstant(i, BaseVT));
|
|
|
|
for (unsigned i = 4; i != 8; ++i)
|
|
|
|
MaskVec.push_back(PermMask.getOperand(i));
|
2006-08-12 01:38:39 +08:00
|
|
|
Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT, &MaskVec[0],MaskVec.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2, Mask);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Floating point cases in the other order.
|
|
|
|
if (X86::isSHUFPMask(PermMask.Val))
|
|
|
|
return Op;
|
|
|
|
if (X86::isPSHUFDMask(PermMask.Val) ||
|
|
|
|
X86::isPSHUFHWMask(PermMask.Val) ||
|
|
|
|
X86::isPSHUFLWMask(PermMask.Val)) {
|
|
|
|
if (V2.getOpcode() != ISD::UNDEF)
|
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1,
|
|
|
|
DAG.getNode(ISD::UNDEF, V1.getValueType()),PermMask);
|
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NumElems == 4) {
|
|
|
|
MVT::ValueType MaskVT = PermMask.getValueType();
|
|
|
|
MVT::ValueType MaskEVT = MVT::getVectorBaseType(MaskVT);
|
Implement four-wide shuffle with 2 shufps if no more than two elements come
from each vector. e.g.
shuffle(G1, G2, 7, 1, 5, 2)
==>
movaps _G2, %xmm0
shufps $151, _G1, %xmm0
shufps $216, %xmm0, %xmm0
llvm-svn: 28011
2006-04-28 15:03:38 +08:00
|
|
|
std::vector<std::pair<int, int> > Locs;
|
|
|
|
Locs.reserve(NumElems);
|
|
|
|
std::vector<SDOperand> Mask1(NumElems, DAG.getNode(ISD::UNDEF, MaskEVT));
|
|
|
|
std::vector<SDOperand> Mask2(NumElems, DAG.getNode(ISD::UNDEF, MaskEVT));
|
|
|
|
unsigned NumHi = 0;
|
|
|
|
unsigned NumLo = 0;
|
|
|
|
// If no more than two elements come from either vector. This can be
|
|
|
|
// implemented with two shuffles. First shuffle gather the elements.
|
|
|
|
// The second shuffle, which takes the first shuffle as both of its
|
|
|
|
// vector operands, put the elements into the right order.
|
|
|
|
for (unsigned i = 0; i != NumElems; ++i) {
|
|
|
|
SDOperand Elt = PermMask.getOperand(i);
|
|
|
|
if (Elt.getOpcode() == ISD::UNDEF) {
|
|
|
|
Locs[i] = std::make_pair(-1, -1);
|
|
|
|
} else {
|
|
|
|
unsigned Val = cast<ConstantSDNode>(Elt)->getValue();
|
|
|
|
if (Val < NumElems) {
|
|
|
|
Locs[i] = std::make_pair(0, NumLo);
|
|
|
|
Mask1[NumLo] = Elt;
|
|
|
|
NumLo++;
|
|
|
|
} else {
|
|
|
|
Locs[i] = std::make_pair(1, NumHi);
|
|
|
|
if (2+NumHi < NumElems)
|
|
|
|
Mask1[2+NumHi] = Elt;
|
|
|
|
NumHi++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NumLo <= 2 && NumHi <= 2) {
|
|
|
|
V1 = DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2,
|
2006-08-12 01:38:39 +08:00
|
|
|
DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&Mask1[0], Mask1.size()));
|
Implement four-wide shuffle with 2 shufps if no more than two elements come
from each vector. e.g.
shuffle(G1, G2, 7, 1, 5, 2)
==>
movaps _G2, %xmm0
shufps $151, _G1, %xmm0
shufps $216, %xmm0, %xmm0
llvm-svn: 28011
2006-04-28 15:03:38 +08:00
|
|
|
for (unsigned i = 0; i != NumElems; ++i) {
|
|
|
|
if (Locs[i].first == -1)
|
|
|
|
continue;
|
|
|
|
else {
|
|
|
|
unsigned Idx = (i < NumElems/2) ? 0 : NumElems;
|
|
|
|
Idx += Locs[i].first * (NumElems/2) + Locs[i].second;
|
|
|
|
Mask2[i] = DAG.getConstant(Idx, MaskEVT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V1,
|
2006-08-12 01:38:39 +08:00
|
|
|
DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&Mask2[0], Mask2.size()));
|
Implement four-wide shuffle with 2 shufps if no more than two elements come
from each vector. e.g.
shuffle(G1, G2, 7, 1, 5, 2)
==>
movaps _G2, %xmm0
shufps $151, _G1, %xmm0
shufps $216, %xmm0, %xmm0
llvm-svn: 28011
2006-04-28 15:03:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Break it into (shuffle shuffle_hi, shuffle_lo).
|
|
|
|
Locs.clear();
|
2006-04-26 04:13:52 +08:00
|
|
|
std::vector<SDOperand> LoMask(NumElems, DAG.getNode(ISD::UNDEF, MaskEVT));
|
|
|
|
std::vector<SDOperand> HiMask(NumElems, DAG.getNode(ISD::UNDEF, MaskEVT));
|
|
|
|
std::vector<SDOperand> *MaskPtr = &LoMask;
|
|
|
|
unsigned MaskIdx = 0;
|
|
|
|
unsigned LoIdx = 0;
|
|
|
|
unsigned HiIdx = NumElems/2;
|
|
|
|
for (unsigned i = 0; i != NumElems; ++i) {
|
|
|
|
if (i == NumElems/2) {
|
|
|
|
MaskPtr = &HiMask;
|
|
|
|
MaskIdx = 1;
|
|
|
|
LoIdx = 0;
|
|
|
|
HiIdx = NumElems/2;
|
|
|
|
}
|
|
|
|
SDOperand Elt = PermMask.getOperand(i);
|
|
|
|
if (Elt.getOpcode() == ISD::UNDEF) {
|
|
|
|
Locs[i] = std::make_pair(-1, -1);
|
|
|
|
} else if (cast<ConstantSDNode>(Elt)->getValue() < NumElems) {
|
|
|
|
Locs[i] = std::make_pair(MaskIdx, LoIdx);
|
|
|
|
(*MaskPtr)[LoIdx] = Elt;
|
|
|
|
LoIdx++;
|
|
|
|
} else {
|
|
|
|
Locs[i] = std::make_pair(MaskIdx, HiIdx);
|
|
|
|
(*MaskPtr)[HiIdx] = Elt;
|
|
|
|
HiIdx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-16 14:45:34 +08:00
|
|
|
SDOperand LoShuffle =
|
|
|
|
DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2,
|
2006-08-12 01:38:39 +08:00
|
|
|
DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&LoMask[0], LoMask.size()));
|
2006-05-16 14:45:34 +08:00
|
|
|
SDOperand HiShuffle =
|
|
|
|
DAG.getNode(ISD::VECTOR_SHUFFLE, VT, V1, V2,
|
2006-08-12 01:38:39 +08:00
|
|
|
DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&HiMask[0], HiMask.size()));
|
2006-04-26 04:13:52 +08:00
|
|
|
std::vector<SDOperand> MaskOps;
|
|
|
|
for (unsigned i = 0; i != NumElems; ++i) {
|
|
|
|
if (Locs[i].first == -1) {
|
|
|
|
MaskOps.push_back(DAG.getNode(ISD::UNDEF, MaskEVT));
|
|
|
|
} else {
|
|
|
|
unsigned Idx = Locs[i].first * NumElems + Locs[i].second;
|
|
|
|
MaskOps.push_back(DAG.getConstant(Idx, MaskEVT));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, LoShuffle, HiShuffle,
|
2006-08-12 01:38:39 +08:00
|
|
|
DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&MaskOps[0], MaskOps.size()));
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SDOperand();
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerEXTRACT_VECTOR_ELT(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
if (!isa<ConstantSDNode>(Op.getOperand(1)))
|
|
|
|
return SDOperand();
|
|
|
|
|
|
|
|
MVT::ValueType VT = Op.getValueType();
|
|
|
|
// TODO: handle v16i8.
|
|
|
|
if (MVT::getSizeInBits(VT) == 16) {
|
|
|
|
// Transform it so it match pextrw which produces a 32-bit result.
|
|
|
|
MVT::ValueType EVT = (MVT::ValueType)(VT+1);
|
|
|
|
SDOperand Extract = DAG.getNode(X86ISD::PEXTRW, EVT,
|
|
|
|
Op.getOperand(0), Op.getOperand(1));
|
|
|
|
SDOperand Assert = DAG.getNode(ISD::AssertZext, EVT, Extract,
|
|
|
|
DAG.getValueType(VT));
|
|
|
|
return DAG.getNode(ISD::TRUNCATE, VT, Assert);
|
|
|
|
} else if (MVT::getSizeInBits(VT) == 32) {
|
|
|
|
SDOperand Vec = Op.getOperand(0);
|
|
|
|
unsigned Idx = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
|
|
|
if (Idx == 0)
|
|
|
|
return Op;
|
|
|
|
// SHUFPS the element to the lowest double word, then movss.
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
|
|
|
|
std::vector<SDOperand> IdxVec;
|
|
|
|
IdxVec.push_back(DAG.getConstant(Idx, MVT::getVectorBaseType(MaskVT)));
|
|
|
|
IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
|
|
|
|
IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
|
|
|
|
IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
|
2006-08-12 01:38:39 +08:00
|
|
|
SDOperand Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&IdxVec[0], IdxVec.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
Vec = DAG.getNode(ISD::VECTOR_SHUFFLE, Vec.getValueType(),
|
|
|
|
Vec, Vec, Mask);
|
|
|
|
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, VT, Vec,
|
2006-06-15 16:14:54 +08:00
|
|
|
DAG.getConstant(0, getPointerTy()));
|
2006-04-26 04:13:52 +08:00
|
|
|
} else if (MVT::getSizeInBits(VT) == 64) {
|
|
|
|
SDOperand Vec = Op.getOperand(0);
|
|
|
|
unsigned Idx = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
|
|
|
if (Idx == 0)
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
// UNPCKHPD the element to the lowest double word, then movsd.
|
|
|
|
// Note if the lower 64 bits of the result of the UNPCKHPD is then stored
|
|
|
|
// to a f64mem, the whole operation is folded into a single MOVHPDmr.
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
|
|
|
|
std::vector<SDOperand> IdxVec;
|
|
|
|
IdxVec.push_back(DAG.getConstant(1, MVT::getVectorBaseType(MaskVT)));
|
|
|
|
IdxVec.push_back(DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(MaskVT)));
|
2006-08-12 01:38:39 +08:00
|
|
|
SDOperand Mask = DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&IdxVec[0], IdxVec.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
Vec = DAG.getNode(ISD::VECTOR_SHUFFLE, Vec.getValueType(),
|
|
|
|
Vec, DAG.getNode(ISD::UNDEF, Vec.getValueType()), Mask);
|
|
|
|
return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, VT, Vec,
|
2006-06-15 16:14:54 +08:00
|
|
|
DAG.getConstant(0, getPointerTy()));
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SDOperand();
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerINSERT_VECTOR_ELT(SDOperand Op, SelectionDAG &DAG) {
|
2006-05-16 15:21:53 +08:00
|
|
|
// Transform it so it match pinsrw which expects a 16-bit value in a GR32
|
2006-04-26 04:13:52 +08:00
|
|
|
// as its second argument.
|
|
|
|
MVT::ValueType VT = Op.getValueType();
|
|
|
|
MVT::ValueType BaseVT = MVT::getVectorBaseType(VT);
|
|
|
|
SDOperand N0 = Op.getOperand(0);
|
|
|
|
SDOperand N1 = Op.getOperand(1);
|
|
|
|
SDOperand N2 = Op.getOperand(2);
|
|
|
|
if (MVT::getSizeInBits(BaseVT) == 16) {
|
|
|
|
if (N1.getValueType() != MVT::i32)
|
|
|
|
N1 = DAG.getNode(ISD::ANY_EXTEND, MVT::i32, N1);
|
|
|
|
if (N2.getValueType() != MVT::i32)
|
|
|
|
N2 = DAG.getConstant(cast<ConstantSDNode>(N2)->getValue(), MVT::i32);
|
|
|
|
return DAG.getNode(X86ISD::PINSRW, VT, N0, N1, N2);
|
|
|
|
} else if (MVT::getSizeInBits(BaseVT) == 32) {
|
|
|
|
unsigned Idx = cast<ConstantSDNode>(N2)->getValue();
|
|
|
|
if (Idx == 0) {
|
|
|
|
// Use a movss.
|
|
|
|
N1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, VT, N1);
|
|
|
|
MVT::ValueType MaskVT = MVT::getIntVectorWithNumElements(4);
|
|
|
|
MVT::ValueType BaseVT = MVT::getVectorBaseType(MaskVT);
|
|
|
|
std::vector<SDOperand> MaskVec;
|
|
|
|
MaskVec.push_back(DAG.getConstant(4, BaseVT));
|
|
|
|
for (unsigned i = 1; i <= 3; ++i)
|
|
|
|
MaskVec.push_back(DAG.getConstant(i, BaseVT));
|
|
|
|
return DAG.getNode(ISD::VECTOR_SHUFFLE, VT, N0, N1,
|
2006-08-12 01:38:39 +08:00
|
|
|
DAG.getNode(ISD::BUILD_VECTOR, MaskVT,
|
|
|
|
&MaskVec[0], MaskVec.size()));
|
2006-04-26 04:13:52 +08:00
|
|
|
} else {
|
|
|
|
// Use two pinsrw instructions to insert a 32 bit value.
|
|
|
|
Idx <<= 1;
|
|
|
|
if (MVT::isFloatingPoint(N1.getValueType())) {
|
|
|
|
if (N1.getOpcode() == ISD::LOAD) {
|
2006-05-16 15:21:53 +08:00
|
|
|
// Just load directly from f32mem to GR32.
|
2006-04-26 04:13:52 +08:00
|
|
|
N1 = DAG.getLoad(MVT::i32, N1.getOperand(0), N1.getOperand(1),
|
|
|
|
N1.getOperand(2));
|
|
|
|
} else {
|
|
|
|
N1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, MVT::v4f32, N1);
|
|
|
|
N1 = DAG.getNode(ISD::BIT_CONVERT, MVT::v4i32, N1);
|
|
|
|
N1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, MVT::i32, N1,
|
2006-06-15 16:14:54 +08:00
|
|
|
DAG.getConstant(0, getPointerTy()));
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
N0 = DAG.getNode(ISD::BIT_CONVERT, MVT::v8i16, N0);
|
|
|
|
N0 = DAG.getNode(X86ISD::PINSRW, MVT::v8i16, N0, N1,
|
2006-06-15 16:14:54 +08:00
|
|
|
DAG.getConstant(Idx, getPointerTy()));
|
2006-04-26 04:13:52 +08:00
|
|
|
N1 = DAG.getNode(ISD::SRL, MVT::i32, N1, DAG.getConstant(16, MVT::i8));
|
|
|
|
N0 = DAG.getNode(X86ISD::PINSRW, MVT::v8i16, N0, N1,
|
2006-06-15 16:14:54 +08:00
|
|
|
DAG.getConstant(Idx+1, getPointerTy()));
|
2006-04-26 04:13:52 +08:00
|
|
|
return DAG.getNode(ISD::BIT_CONVERT, VT, N0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SDOperand();
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerSCALAR_TO_VECTOR(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand AnyExt = DAG.getNode(ISD::ANY_EXTEND, MVT::i32, Op.getOperand(0));
|
|
|
|
return DAG.getNode(X86ISD::S2VEC, Op.getValueType(), AnyExt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConstantPool, JumpTable, GlobalAddress, and ExternalSymbol are lowered as
|
|
|
|
// their target countpart wrapped in the X86ISD::Wrapper node. Suppose N is
|
|
|
|
// one of the above mentioned nodes. It has to be wrapped because otherwise
|
|
|
|
// Select(N) returns N. So the raw TargetGlobalAddress nodes, etc. can only
|
|
|
|
// be used to form addressing mode. These wrapped nodes will be selected
|
|
|
|
// into MOV32ri.
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerConstantPool(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
|
|
|
|
SDOperand Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(),
|
2006-09-13 05:04:05 +08:00
|
|
|
DAG.getTargetConstantPool(CP->getConstVal(),
|
|
|
|
getPointerTy(),
|
|
|
|
CP->getAlignment()));
|
2006-04-26 04:13:52 +08:00
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
|
|
// With PIC, the address is actually $g + Offset.
|
2006-09-08 14:48:29 +08:00
|
|
|
if (!Subtarget->is64Bit() &&
|
|
|
|
getTargetMachine().getRelocationModel() == Reloc::PIC_)
|
2006-04-26 04:13:52 +08:00
|
|
|
Result = DAG.getNode(ISD::ADD, getPointerTy(),
|
|
|
|
DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()), Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
|
|
|
|
SDOperand Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(),
|
2006-05-16 14:45:34 +08:00
|
|
|
DAG.getTargetGlobalAddress(GV,
|
|
|
|
getPointerTy()));
|
2006-04-26 04:13:52 +08:00
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
|
|
// With PIC, the address is actually $g + Offset.
|
2006-09-08 14:48:29 +08:00
|
|
|
if (!Subtarget->is64Bit() &&
|
|
|
|
getTargetMachine().getRelocationModel() == Reloc::PIC_)
|
2006-04-26 04:13:52 +08:00
|
|
|
Result = DAG.getNode(ISD::ADD, getPointerTy(),
|
2006-05-16 14:45:34 +08:00
|
|
|
DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()),
|
|
|
|
Result);
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
// For Darwin, external and weak symbols are indirect, so we want to load
|
|
|
|
// the value at address GV, not the value of GV itself. This means that
|
|
|
|
// the GlobalAddress must be in the base or index register of the address,
|
|
|
|
// not the GV offset field.
|
|
|
|
if (getTargetMachine().getRelocationModel() != Reloc::Static &&
|
|
|
|
DarwinGVRequiresExtraLoad(GV))
|
2006-09-08 14:48:29 +08:00
|
|
|
Result = DAG.getLoad(getPointerTy(), DAG.getEntryNode(),
|
2006-04-26 04:13:52 +08:00
|
|
|
Result, DAG.getSrcValue(NULL));
|
2006-09-15 02:23:27 +08:00
|
|
|
} else if (Subtarget->isTargetCygwin() || Subtarget->isTargetWindows()) {
|
|
|
|
// FIXME: What's about PIC?
|
|
|
|
if (WindowsGVRequiresExtraLoad(GV)) {
|
|
|
|
Result = DAG.getLoad(getPointerTy(), DAG.getEntryNode(),
|
|
|
|
Result, DAG.getSrcValue(NULL));
|
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
2006-09-15 02:23:27 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerExternalSymbol(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
const char *Sym = cast<ExternalSymbolSDNode>(Op)->getSymbol();
|
|
|
|
SDOperand Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(),
|
2006-05-16 14:45:34 +08:00
|
|
|
DAG.getTargetExternalSymbol(Sym,
|
|
|
|
getPointerTy()));
|
2006-04-26 04:13:52 +08:00
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
|
|
// With PIC, the address is actually $g + Offset.
|
2006-09-08 14:48:29 +08:00
|
|
|
if (!Subtarget->is64Bit() &&
|
|
|
|
getTargetMachine().getRelocationModel() == Reloc::PIC_)
|
2006-04-26 04:13:52 +08:00
|
|
|
Result = DAG.getNode(ISD::ADD, getPointerTy(),
|
2006-05-16 14:45:34 +08:00
|
|
|
DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()),
|
|
|
|
Result);
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerShift(SDOperand Op, SelectionDAG &DAG) {
|
2006-01-10 02:33:28 +08:00
|
|
|
assert(Op.getNumOperands() == 3 && Op.getValueType() == MVT::i32 &&
|
|
|
|
"Not an i64 shift!");
|
|
|
|
bool isSRA = Op.getOpcode() == ISD::SRA_PARTS;
|
|
|
|
SDOperand ShOpLo = Op.getOperand(0);
|
|
|
|
SDOperand ShOpHi = Op.getOperand(1);
|
|
|
|
SDOperand ShAmt = Op.getOperand(2);
|
2006-09-11 10:19:56 +08:00
|
|
|
SDOperand Tmp1 = isSRA ?
|
|
|
|
DAG.getNode(ISD::SRA, MVT::i32, ShOpHi, DAG.getConstant(31, MVT::i8)) :
|
|
|
|
DAG.getConstant(0, MVT::i32);
|
2006-01-10 02:33:28 +08:00
|
|
|
|
|
|
|
SDOperand Tmp2, Tmp3;
|
|
|
|
if (Op.getOpcode() == ISD::SHL_PARTS) {
|
|
|
|
Tmp2 = DAG.getNode(X86ISD::SHLD, MVT::i32, ShOpHi, ShOpLo, ShAmt);
|
|
|
|
Tmp3 = DAG.getNode(ISD::SHL, MVT::i32, ShOpLo, ShAmt);
|
|
|
|
} else {
|
|
|
|
Tmp2 = DAG.getNode(X86ISD::SHRD, MVT::i32, ShOpLo, ShOpHi, ShAmt);
|
2006-01-19 09:46:14 +08:00
|
|
|
Tmp3 = DAG.getNode(isSRA ? ISD::SRA : ISD::SRL, MVT::i32, ShOpHi, ShAmt);
|
2006-01-10 02:33:28 +08:00
|
|
|
}
|
|
|
|
|
2006-09-11 10:19:56 +08:00
|
|
|
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
|
|
|
|
SDOperand AndNode = DAG.getNode(ISD::AND, MVT::i8, ShAmt,
|
|
|
|
DAG.getConstant(32, MVT::i8));
|
|
|
|
SDOperand COps[]={DAG.getEntryNode(), AndNode, DAG.getConstant(0, MVT::i8)};
|
|
|
|
SDOperand InFlag = DAG.getNode(X86ISD::CMP, VTs, 2, COps, 3).getValue(1);
|
2006-01-10 02:33:28 +08:00
|
|
|
|
|
|
|
SDOperand Hi, Lo;
|
2006-01-10 04:49:21 +08:00
|
|
|
SDOperand CC = DAG.getConstant(X86ISD::COND_NE, MVT::i8);
|
2006-01-10 02:33:28 +08:00
|
|
|
|
2006-09-11 10:19:56 +08:00
|
|
|
VTs = DAG.getNodeValueTypes(MVT::i32, MVT::Flag);
|
|
|
|
SmallVector<SDOperand, 4> Ops;
|
2006-01-10 02:33:28 +08:00
|
|
|
if (Op.getOpcode() == ISD::SHL_PARTS) {
|
|
|
|
Ops.push_back(Tmp2);
|
|
|
|
Ops.push_back(Tmp3);
|
|
|
|
Ops.push_back(CC);
|
|
|
|
Ops.push_back(InFlag);
|
2006-09-11 10:19:56 +08:00
|
|
|
Hi = DAG.getNode(X86ISD::CMOV, VTs, 2, &Ops[0], Ops.size());
|
2006-01-10 02:33:28 +08:00
|
|
|
InFlag = Hi.getValue(1);
|
|
|
|
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Tmp3);
|
|
|
|
Ops.push_back(Tmp1);
|
|
|
|
Ops.push_back(CC);
|
|
|
|
Ops.push_back(InFlag);
|
2006-09-11 10:19:56 +08:00
|
|
|
Lo = DAG.getNode(X86ISD::CMOV, VTs, 2, &Ops[0], Ops.size());
|
2006-01-10 02:33:28 +08:00
|
|
|
} else {
|
|
|
|
Ops.push_back(Tmp2);
|
|
|
|
Ops.push_back(Tmp3);
|
|
|
|
Ops.push_back(CC);
|
2006-01-10 06:29:54 +08:00
|
|
|
Ops.push_back(InFlag);
|
2006-09-11 10:19:56 +08:00
|
|
|
Lo = DAG.getNode(X86ISD::CMOV, VTs, 2, &Ops[0], Ops.size());
|
2006-01-10 02:33:28 +08:00
|
|
|
InFlag = Lo.getValue(1);
|
|
|
|
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Tmp3);
|
|
|
|
Ops.push_back(Tmp1);
|
|
|
|
Ops.push_back(CC);
|
|
|
|
Ops.push_back(InFlag);
|
2006-09-11 10:19:56 +08:00
|
|
|
Hi = DAG.getNode(X86ISD::CMOV, VTs, 2, &Ops[0], Ops.size());
|
2006-01-10 02:33:28 +08:00
|
|
|
}
|
|
|
|
|
2006-09-11 10:19:56 +08:00
|
|
|
VTs = DAG.getNodeValueTypes(MVT::i32, MVT::i32);
|
2006-01-10 02:33:28 +08:00
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Lo);
|
|
|
|
Ops.push_back(Hi);
|
2006-09-11 10:19:56 +08:00
|
|
|
return DAG.getNode(ISD::MERGE_VALUES, VTs, 2, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerSINT_TO_FP(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
assert(Op.getOperand(0).getValueType() <= MVT::i64 &&
|
|
|
|
Op.getOperand(0).getValueType() >= MVT::i16 &&
|
|
|
|
"Unknown SINT_TO_FP to lower!");
|
2006-01-13 06:54:21 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand Result;
|
|
|
|
MVT::ValueType SrcVT = Op.getOperand(0).getValueType();
|
|
|
|
unsigned Size = MVT::getSizeInBits(SrcVT)/8;
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
|
|
|
|
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
|
|
|
|
SDOperand Chain = DAG.getNode(ISD::STORE, MVT::Other,
|
|
|
|
DAG.getEntryNode(), Op.getOperand(0),
|
|
|
|
StackSlot, DAG.getSrcValue(NULL));
|
|
|
|
|
|
|
|
// Build the FILD
|
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::f64);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
if (X86ScalarSSE) Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(StackSlot);
|
|
|
|
Ops.push_back(DAG.getValueType(SrcVT));
|
|
|
|
Result = DAG.getNode(X86ScalarSSE ? X86ISD::FILD_FLAG :X86ISD::FILD,
|
2006-08-08 10:23:42 +08:00
|
|
|
Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
if (X86ScalarSSE) {
|
|
|
|
Chain = Result.getValue(1);
|
|
|
|
SDOperand InFlag = Result.getValue(2);
|
|
|
|
|
|
|
|
// FIXME: Currently the FST is flagged to the FILD_FLAG. This
|
|
|
|
// shouldn't be necessary except that RFP cannot be live across
|
|
|
|
// multiple blocks. When stackifier is fixed, they can be uncoupled.
|
2005-11-15 08:40:23 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
2006-04-26 04:13:52 +08:00
|
|
|
int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8);
|
2005-11-15 08:40:23 +08:00
|
|
|
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
|
2006-01-13 06:54:21 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
2006-01-30 16:02:57 +08:00
|
|
|
Tys.push_back(MVT::Other);
|
2005-11-15 08:40:23 +08:00
|
|
|
std::vector<SDOperand> Ops;
|
2006-01-13 06:54:21 +08:00
|
|
|
Ops.push_back(Chain);
|
2006-04-26 04:13:52 +08:00
|
|
|
Ops.push_back(Result);
|
2005-11-15 08:40:23 +08:00
|
|
|
Ops.push_back(StackSlot);
|
2006-04-26 04:13:52 +08:00
|
|
|
Ops.push_back(DAG.getValueType(Op.getValueType()));
|
|
|
|
Ops.push_back(InFlag);
|
2006-08-08 10:23:42 +08:00
|
|
|
Chain = DAG.getNode(X86ISD::FST, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
Result = DAG.getLoad(Op.getValueType(), Chain, StackSlot,
|
|
|
|
DAG.getSrcValue(NULL));
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerFP_TO_SINT(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
assert(Op.getValueType() <= MVT::i64 && Op.getValueType() >= MVT::i16 &&
|
|
|
|
"Unknown FP_TO_SINT to lower!");
|
|
|
|
// We lower FP->sint64 into FISTP64, followed by a load, all to a temporary
|
|
|
|
// stack slot.
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
unsigned MemSize = MVT::getSizeInBits(Op.getValueType())/8;
|
|
|
|
int SSFI = MF.getFrameInfo()->CreateStackObject(MemSize, MemSize);
|
|
|
|
SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
|
|
|
|
|
|
|
|
unsigned Opc;
|
|
|
|
switch (Op.getValueType()) {
|
2005-11-15 08:40:23 +08:00
|
|
|
default: assert(0 && "Invalid FP_TO_SINT to lower!");
|
|
|
|
case MVT::i16: Opc = X86ISD::FP_TO_INT16_IN_MEM; break;
|
|
|
|
case MVT::i32: Opc = X86ISD::FP_TO_INT32_IN_MEM; break;
|
|
|
|
case MVT::i64: Opc = X86ISD::FP_TO_INT64_IN_MEM; break;
|
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
SDOperand Chain = DAG.getEntryNode();
|
|
|
|
SDOperand Value = Op.getOperand(0);
|
|
|
|
if (X86ScalarSSE) {
|
|
|
|
assert(Op.getValueType() == MVT::i64 && "Invalid FP_TO_SINT to lower!");
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value, StackSlot,
|
|
|
|
DAG.getSrcValue(0));
|
2005-11-21 06:01:40 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
2006-04-26 04:13:52 +08:00
|
|
|
Tys.push_back(MVT::f64);
|
2005-11-21 06:01:40 +08:00
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
std::vector<SDOperand> Ops;
|
2006-04-26 04:13:52 +08:00
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(StackSlot);
|
|
|
|
Ops.push_back(DAG.getValueType(Op.getOperand(0).getValueType()));
|
2006-08-08 10:23:42 +08:00
|
|
|
Value = DAG.getNode(X86ISD::FLD, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
Chain = Value.getValue(1);
|
|
|
|
SSFI = MF.getFrameInfo()->CreateStackObject(MemSize, MemSize);
|
|
|
|
StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
|
2005-11-21 05:41:10 +08:00
|
|
|
}
|
2006-01-06 08:43:03 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
// Build the FP_TO_INT*_IN_MEM
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Value);
|
|
|
|
Ops.push_back(StackSlot);
|
2006-08-11 15:35:45 +08:00
|
|
|
SDOperand FIST = DAG.getNode(Opc, MVT::Other, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
// Load the result.
|
|
|
|
return DAG.getLoad(Op.getValueType(), FIST, StackSlot,
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerFABS(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
MVT::ValueType VT = Op.getValueType();
|
|
|
|
const Type *OpNTy = MVT::getTypeForValueType(VT);
|
|
|
|
std::vector<Constant*> CV;
|
|
|
|
if (VT == MVT::f64) {
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, BitsToDouble(~(1ULL << 63))));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
} else {
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, BitsToFloat(~(1U << 31))));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
}
|
|
|
|
Constant *CS = ConstantStruct::get(CV);
|
|
|
|
SDOperand CPIdx = DAG.getConstantPool(CS, getPointerTy(), 4);
|
2006-08-11 17:08:15 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(VT);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
SmallVector<SDOperand, 3> Ops;
|
|
|
|
Ops.push_back(DAG.getEntryNode());
|
|
|
|
Ops.push_back(CPIdx);
|
|
|
|
Ops.push_back(DAG.getSrcValue(NULL));
|
|
|
|
SDOperand Mask = DAG.getNode(X86ISD::LOAD_PACK, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
return DAG.getNode(X86ISD::FAND, VT, Op.getOperand(0), Mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerFNEG(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
MVT::ValueType VT = Op.getValueType();
|
|
|
|
const Type *OpNTy = MVT::getTypeForValueType(VT);
|
|
|
|
std::vector<Constant*> CV;
|
|
|
|
if (VT == MVT::f64) {
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, BitsToDouble(1ULL << 63)));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
} else {
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, BitsToFloat(1U << 31)));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
CV.push_back(ConstantFP::get(OpNTy, 0.0));
|
|
|
|
}
|
|
|
|
Constant *CS = ConstantStruct::get(CV);
|
|
|
|
SDOperand CPIdx = DAG.getConstantPool(CS, getPointerTy(), 4);
|
2006-08-11 17:08:15 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(VT);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
SmallVector<SDOperand, 3> Ops;
|
|
|
|
Ops.push_back(DAG.getEntryNode());
|
|
|
|
Ops.push_back(CPIdx);
|
|
|
|
Ops.push_back(DAG.getSrcValue(NULL));
|
|
|
|
SDOperand Mask = DAG.getNode(X86ISD::LOAD_PACK, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
return DAG.getNode(X86ISD::FXOR, VT, Op.getOperand(0), Mask);
|
|
|
|
}
|
|
|
|
|
2006-09-11 10:19:56 +08:00
|
|
|
SDOperand X86TargetLowering::LowerSETCC(SDOperand Op, SelectionDAG &DAG,
|
|
|
|
SDOperand Chain) {
|
2006-04-26 04:13:52 +08:00
|
|
|
assert(Op.getValueType() == MVT::i8 && "SetCC type must be 8-bit integer");
|
|
|
|
SDOperand Cond;
|
2006-09-11 10:19:56 +08:00
|
|
|
SDOperand Op0 = Op.getOperand(0);
|
|
|
|
SDOperand Op1 = Op.getOperand(1);
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand CC = Op.getOperand(2);
|
|
|
|
ISD::CondCode SetCCOpcode = cast<CondCodeSDNode>(CC)->get();
|
2006-09-11 10:19:56 +08:00
|
|
|
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
|
2006-04-26 04:13:52 +08:00
|
|
|
bool isFP = MVT::isFloatingPoint(Op.getOperand(1).getValueType());
|
|
|
|
unsigned X86CC;
|
2006-09-11 10:19:56 +08:00
|
|
|
|
|
|
|
VTs = DAG.getNodeValueTypes(MVT::i8, MVT::Flag);
|
2006-09-13 11:22:10 +08:00
|
|
|
if (translateX86CC(cast<CondCodeSDNode>(CC)->get(), isFP, X86CC,
|
|
|
|
Op0, Op1, DAG)) {
|
2006-09-11 10:19:56 +08:00
|
|
|
SDOperand Ops1[] = { Chain, Op0, Op1 };
|
|
|
|
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, Ops1, 3).getValue(1);
|
|
|
|
SDOperand Ops2[] = { DAG.getConstant(X86CC, MVT::i8), Cond };
|
|
|
|
return DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
|
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
|
2006-09-11 10:19:56 +08:00
|
|
|
assert(isFP && "Illegal integer SetCC!");
|
|
|
|
|
|
|
|
SDOperand COps[] = { Chain, Op0, Op1 };
|
|
|
|
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, COps, 3).getValue(1);
|
|
|
|
|
|
|
|
switch (SetCCOpcode) {
|
|
|
|
default: assert(false && "Illegal floating point SetCC!");
|
|
|
|
case ISD::SETOEQ: { // !PF & ZF
|
|
|
|
SDOperand Ops1[] = { DAG.getConstant(X86ISD::COND_NP, MVT::i8), Cond };
|
|
|
|
SDOperand Tmp1 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops1, 2);
|
|
|
|
SDOperand Ops2[] = { DAG.getConstant(X86ISD::COND_E, MVT::i8),
|
|
|
|
Tmp1.getValue(1) };
|
|
|
|
SDOperand Tmp2 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
|
|
|
|
return DAG.getNode(ISD::AND, MVT::i8, Tmp1, Tmp2);
|
|
|
|
}
|
|
|
|
case ISD::SETUNE: { // PF | !ZF
|
|
|
|
SDOperand Ops1[] = { DAG.getConstant(X86ISD::COND_P, MVT::i8), Cond };
|
|
|
|
SDOperand Tmp1 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops1, 2);
|
|
|
|
SDOperand Ops2[] = { DAG.getConstant(X86ISD::COND_NE, MVT::i8),
|
|
|
|
Tmp1.getValue(1) };
|
|
|
|
SDOperand Tmp2 = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
|
|
|
|
return DAG.getNode(ISD::OR, MVT::i8, Tmp1, Tmp2);
|
|
|
|
}
|
2005-12-22 04:21:51 +08:00
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
2006-01-26 10:13:10 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand X86TargetLowering::LowerSELECT(SDOperand Op, SelectionDAG &DAG) {
|
2006-09-11 10:19:56 +08:00
|
|
|
bool addTest = true;
|
|
|
|
SDOperand Chain = DAG.getEntryNode();
|
|
|
|
SDOperand Cond = Op.getOperand(0);
|
|
|
|
SDOperand CC;
|
|
|
|
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
|
|
|
|
|
|
|
|
if (Cond.getOpcode() == ISD::SETCC)
|
|
|
|
Cond = LowerSETCC(Cond, DAG, Chain);
|
|
|
|
|
|
|
|
if (Cond.getOpcode() == X86ISD::SETCC) {
|
|
|
|
CC = Cond.getOperand(0);
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
// If condition flag is set by a X86ISD::CMP, then make a copy of it
|
2006-09-11 10:19:56 +08:00
|
|
|
// (since flag operand cannot be shared). Use it as the condition setting
|
|
|
|
// operand in place of the X86ISD::SETCC.
|
|
|
|
// If the X86ISD::SETCC has more than one use, then perhaps it's better
|
2006-04-26 04:13:52 +08:00
|
|
|
// to use a test instead of duplicating the X86ISD::CMP (for register
|
2006-09-11 10:19:56 +08:00
|
|
|
// pressure reason)?
|
|
|
|
SDOperand Cmp = Cond.getOperand(1);
|
|
|
|
unsigned Opc = Cmp.getOpcode();
|
|
|
|
bool IllegalFPCMov = !X86ScalarSSE &&
|
|
|
|
MVT::isFloatingPoint(Op.getValueType()) &&
|
|
|
|
!hasFPCMov(cast<ConstantSDNode>(CC)->getSignExtended());
|
|
|
|
if ((Opc == X86ISD::CMP || Opc == X86ISD::COMI || Opc == X86ISD::UCOMI) &&
|
|
|
|
!IllegalFPCMov) {
|
|
|
|
SDOperand Ops[] = { Chain, Cmp.getOperand(1), Cmp.getOperand(2) };
|
|
|
|
Cond = DAG.getNode(Opc, VTs, 2, Ops, 3);
|
|
|
|
addTest = false;
|
|
|
|
}
|
|
|
|
}
|
2006-01-11 04:26:56 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
if (addTest) {
|
|
|
|
CC = DAG.getConstant(X86ISD::COND_NE, MVT::i8);
|
2006-09-11 10:19:56 +08:00
|
|
|
SDOperand Ops[] = { Chain, Cond, DAG.getConstant(0, MVT::i8) };
|
|
|
|
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, Ops, 3);
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
2006-01-10 02:33:28 +08:00
|
|
|
|
2006-09-11 10:19:56 +08:00
|
|
|
VTs = DAG.getNodeValueTypes(Op.getValueType(), MVT::Flag);
|
|
|
|
SmallVector<SDOperand, 4> Ops;
|
2006-04-26 04:13:52 +08:00
|
|
|
// X86ISD::CMOV means set the result (which is operand 1) to the RHS if
|
|
|
|
// condition is true.
|
|
|
|
Ops.push_back(Op.getOperand(2));
|
|
|
|
Ops.push_back(Op.getOperand(1));
|
|
|
|
Ops.push_back(CC);
|
2006-09-11 10:19:56 +08:00
|
|
|
Ops.push_back(Cond.getValue(1));
|
|
|
|
return DAG.getNode(X86ISD::CMOV, VTs, 2, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
2006-01-26 10:13:10 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand X86TargetLowering::LowerBRCOND(SDOperand Op, SelectionDAG &DAG) {
|
2006-09-11 10:19:56 +08:00
|
|
|
bool addTest = true;
|
|
|
|
SDOperand Chain = Op.getOperand(0);
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand Cond = Op.getOperand(1);
|
|
|
|
SDOperand Dest = Op.getOperand(2);
|
|
|
|
SDOperand CC;
|
2006-09-11 10:19:56 +08:00
|
|
|
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
if (Cond.getOpcode() == ISD::SETCC)
|
2006-09-11 10:19:56 +08:00
|
|
|
Cond = LowerSETCC(Cond, DAG, Chain);
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
if (Cond.getOpcode() == X86ISD::SETCC) {
|
2006-09-11 10:19:56 +08:00
|
|
|
CC = Cond.getOperand(0);
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
// If condition flag is set by a X86ISD::CMP, then make a copy of it
|
2006-09-11 10:19:56 +08:00
|
|
|
// (since flag operand cannot be shared). Use it as the condition setting
|
|
|
|
// operand in place of the X86ISD::SETCC.
|
|
|
|
// If the X86ISD::SETCC has more than one use, then perhaps it's better
|
2006-04-26 04:13:52 +08:00
|
|
|
// to use a test instead of duplicating the X86ISD::CMP (for register
|
2006-09-11 10:19:56 +08:00
|
|
|
// pressure reason)?
|
|
|
|
SDOperand Cmp = Cond.getOperand(1);
|
|
|
|
unsigned Opc = Cmp.getOpcode();
|
|
|
|
if (Opc == X86ISD::CMP || Opc == X86ISD::COMI || Opc == X86ISD::UCOMI) {
|
|
|
|
SDOperand Ops[] = { Chain, Cmp.getOperand(1), Cmp.getOperand(2) };
|
|
|
|
Cond = DAG.getNode(Opc, VTs, 2, Ops, 3);
|
|
|
|
addTest = false;
|
|
|
|
}
|
|
|
|
}
|
2006-01-13 09:03:02 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
if (addTest) {
|
|
|
|
CC = DAG.getConstant(X86ISD::COND_NE, MVT::i8);
|
2006-09-11 10:19:56 +08:00
|
|
|
SDOperand Ops[] = { Chain, Cond, DAG.getConstant(0, MVT::i8) };
|
|
|
|
Cond = DAG.getNode(X86ISD::CMP, VTs, 2, Ops, 3);
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
return DAG.getNode(X86ISD::BRCOND, Op.getValueType(),
|
2006-09-11 10:19:56 +08:00
|
|
|
Cond, Op.getOperand(2), CC, Cond.getValue(1));
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
2006-02-16 08:21:07 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand X86TargetLowering::LowerJumpTable(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
|
|
|
|
SDOperand Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(),
|
|
|
|
DAG.getTargetJumpTable(JT->getIndex(),
|
|
|
|
getPointerTy()));
|
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
|
|
// With PIC, the address is actually $g + Offset.
|
2006-09-08 14:48:29 +08:00
|
|
|
if (!Subtarget->is64Bit() &&
|
|
|
|
getTargetMachine().getRelocationModel() == Reloc::PIC_)
|
2006-04-26 04:13:52 +08:00
|
|
|
Result = DAG.getNode(ISD::ADD, getPointerTy(),
|
2006-05-16 14:45:34 +08:00
|
|
|
DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()),
|
|
|
|
Result);
|
2006-02-18 08:15:05 +08:00
|
|
|
}
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
return Result;
|
|
|
|
}
|
2006-02-24 04:41:18 +08:00
|
|
|
|
2006-05-25 08:59:30 +08:00
|
|
|
SDOperand X86TargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
2006-09-21 06:03:51 +08:00
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
return LowerX86_64CCCCallTo(Op, DAG);
|
2006-05-25 08:59:30 +08:00
|
|
|
else
|
2006-09-21 06:03:51 +08:00
|
|
|
switch (CallingConv) {
|
|
|
|
case CallingConv::Fast:
|
|
|
|
if (EnableFastCC) {
|
|
|
|
return LowerFastCCCallTo(Op, DAG, false);
|
|
|
|
}
|
|
|
|
// Falls through
|
|
|
|
case CallingConv::C:
|
|
|
|
case CallingConv::CSRet:
|
|
|
|
return LowerCCCCallTo(Op, DAG);
|
|
|
|
case CallingConv::X86_StdCall:
|
|
|
|
return LowerStdCallCCCallTo(Op, DAG);
|
|
|
|
case CallingConv::X86_FastCall:
|
|
|
|
return LowerFastCCCallTo(Op, DAG, true);
|
|
|
|
default:
|
|
|
|
assert(0 && "Unsupported calling convention");
|
|
|
|
}
|
2006-05-25 08:59:30 +08:00
|
|
|
}
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand X86TargetLowering::LowerRET(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand Copy;
|
2006-01-28 05:09:22 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
switch(Op.getNumOperands()) {
|
2006-01-28 05:09:22 +08:00
|
|
|
default:
|
|
|
|
assert(0 && "Do not know how to return this many arguments!");
|
|
|
|
abort();
|
2006-04-18 04:32:50 +08:00
|
|
|
case 1: // ret void.
|
2006-01-28 05:09:22 +08:00
|
|
|
return DAG.getNode(X86ISD::RET_FLAG, MVT::Other, Op.getOperand(0),
|
2006-04-26 04:13:52 +08:00
|
|
|
DAG.getConstant(getBytesToPopOnReturn(), MVT::i16));
|
2006-05-27 07:10:12 +08:00
|
|
|
case 3: {
|
2006-01-28 05:09:22 +08:00
|
|
|
MVT::ValueType ArgVT = Op.getOperand(1).getValueType();
|
2006-04-18 04:32:50 +08:00
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
if (MVT::isVector(ArgVT) ||
|
|
|
|
(Subtarget->is64Bit() && MVT::isFloatingPoint(ArgVT))) {
|
2006-04-18 04:32:50 +08:00
|
|
|
// Integer or FP vector result -> XMM0.
|
|
|
|
if (DAG.getMachineFunction().liveout_empty())
|
|
|
|
DAG.getMachineFunction().addLiveOut(X86::XMM0);
|
|
|
|
Copy = DAG.getCopyToReg(Op.getOperand(0), X86::XMM0, Op.getOperand(1),
|
|
|
|
SDOperand());
|
|
|
|
} else if (MVT::isInteger(ArgVT)) {
|
2006-09-08 14:48:29 +08:00
|
|
|
// Integer result -> EAX / RAX.
|
|
|
|
// The C calling convention guarantees the return value has been
|
|
|
|
// promoted to at least MVT::i32. The X86-64 ABI doesn't require the
|
|
|
|
// value to be promoted MVT::i64. So we don't have to extend it to
|
|
|
|
// 64-bit. Return the value in EAX, but mark RAX as liveout.
|
|
|
|
unsigned Reg = Subtarget->is64Bit() ? X86::RAX : X86::EAX;
|
2006-04-18 04:32:50 +08:00
|
|
|
if (DAG.getMachineFunction().liveout_empty())
|
2006-09-08 14:48:29 +08:00
|
|
|
DAG.getMachineFunction().addLiveOut(Reg);
|
2006-04-18 04:32:50 +08:00
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
Reg = (ArgVT == MVT::i64) ? X86::RAX : X86::EAX;
|
|
|
|
Copy = DAG.getCopyToReg(Op.getOperand(0), Reg, Op.getOperand(1),
|
2006-01-28 05:09:22 +08:00
|
|
|
SDOperand());
|
2006-04-18 04:32:50 +08:00
|
|
|
} else if (!X86ScalarSSE) {
|
|
|
|
// FP return with fp-stack value.
|
|
|
|
if (DAG.getMachineFunction().liveout_empty())
|
|
|
|
DAG.getMachineFunction().addLiveOut(X86::ST0);
|
|
|
|
|
2006-01-28 05:09:22 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op.getOperand(0));
|
|
|
|
Ops.push_back(Op.getOperand(1));
|
2006-08-11 15:35:45 +08:00
|
|
|
Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, &Ops[0], Ops.size());
|
2006-01-28 05:09:22 +08:00
|
|
|
} else {
|
2006-04-18 04:32:50 +08:00
|
|
|
// FP return with ScalarSSE (return on fp-stack).
|
|
|
|
if (DAG.getMachineFunction().liveout_empty())
|
|
|
|
DAG.getMachineFunction().addLiveOut(X86::ST0);
|
|
|
|
|
2006-02-01 08:20:21 +08:00
|
|
|
SDOperand MemLoc;
|
|
|
|
SDOperand Chain = Op.getOperand(0);
|
2006-02-01 07:19:54 +08:00
|
|
|
SDOperand Value = Op.getOperand(1);
|
|
|
|
|
2006-02-01 09:19:32 +08:00
|
|
|
if (Value.getOpcode() == ISD::LOAD &&
|
|
|
|
(Chain == Value.getValue(1) || Chain == Value.getOperand(0))) {
|
2006-02-01 07:19:54 +08:00
|
|
|
Chain = Value.getOperand(0);
|
|
|
|
MemLoc = Value.getOperand(1);
|
|
|
|
} else {
|
|
|
|
// Spill the value to memory and reload it into top of stack.
|
|
|
|
unsigned Size = MVT::getSizeInBits(ArgVT)/8;
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
|
|
|
|
MemLoc = DAG.getFrameIndex(SSFI, getPointerTy());
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
|
|
|
|
Value, MemLoc, DAG.getSrcValue(0));
|
|
|
|
}
|
2006-01-28 05:09:22 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::f64);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
2006-02-01 07:19:54 +08:00
|
|
|
Ops.push_back(MemLoc);
|
2006-01-28 05:09:22 +08:00
|
|
|
Ops.push_back(DAG.getValueType(ArgVT));
|
2006-08-11 15:35:45 +08:00
|
|
|
Copy = DAG.getNode(X86ISD::FLD, Tys, &Ops[0], Ops.size());
|
2006-01-28 05:09:22 +08:00
|
|
|
Tys.clear();
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Copy.getValue(1));
|
|
|
|
Ops.push_back(Copy);
|
2006-08-11 15:35:45 +08:00
|
|
|
Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, &Ops[0], Ops.size());
|
2006-01-28 05:09:22 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2006-09-08 14:48:29 +08:00
|
|
|
case 5: {
|
|
|
|
unsigned Reg1 = Subtarget->is64Bit() ? X86::RAX : X86::EAX;
|
|
|
|
unsigned Reg2 = Subtarget->is64Bit() ? X86::RDX : X86::EDX;
|
2006-04-18 04:32:50 +08:00
|
|
|
if (DAG.getMachineFunction().liveout_empty()) {
|
2006-09-08 14:48:29 +08:00
|
|
|
DAG.getMachineFunction().addLiveOut(Reg1);
|
|
|
|
DAG.getMachineFunction().addLiveOut(Reg2);
|
2006-04-18 04:32:50 +08:00
|
|
|
}
|
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
Copy = DAG.getCopyToReg(Op.getOperand(0), Reg2, Op.getOperand(3),
|
2006-01-28 05:09:22 +08:00
|
|
|
SDOperand());
|
2006-09-08 14:48:29 +08:00
|
|
|
Copy = DAG.getCopyToReg(Copy, Reg1, Op.getOperand(1), Copy.getValue(1));
|
2006-01-28 05:09:22 +08:00
|
|
|
break;
|
2006-09-08 14:48:29 +08:00
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
return DAG.getNode(X86ISD::RET_FLAG, MVT::Other,
|
2006-09-08 14:48:29 +08:00
|
|
|
Copy, DAG.getConstant(getBytesToPopOnReturn(), MVT::i16),
|
2006-04-26 04:13:52 +08:00
|
|
|
Copy.getValue(1));
|
|
|
|
}
|
2006-04-20 06:48:17 +08:00
|
|
|
|
2006-04-26 09:20:17 +08:00
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG) {
|
2006-06-07 07:30:24 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
const Function* Fn = MF.getFunction();
|
|
|
|
if (Fn->hasExternalLinkage() &&
|
2006-09-18 04:25:45 +08:00
|
|
|
Subtarget->isTargetCygwin() &&
|
2006-06-09 14:24:42 +08:00
|
|
|
Fn->getName() == "main")
|
2006-06-07 07:30:24 +08:00
|
|
|
MF.getInfo<X86FunctionInfo>()->setForceFramePointer(true);
|
|
|
|
|
2006-05-24 05:06:34 +08:00
|
|
|
unsigned CC = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit())
|
|
|
|
return LowerX86_64CCCArguments(Op, DAG);
|
2006-05-24 05:06:34 +08:00
|
|
|
else
|
2006-09-21 06:03:51 +08:00
|
|
|
switch(CC) {
|
|
|
|
case CallingConv::Fast:
|
|
|
|
if (EnableFastCC) {
|
|
|
|
return LowerFastCCArguments(Op, DAG);
|
|
|
|
}
|
|
|
|
// Falls through
|
|
|
|
case CallingConv::C:
|
|
|
|
case CallingConv::CSRet:
|
|
|
|
return LowerCCCArguments(Op, DAG);
|
|
|
|
case CallingConv::X86_StdCall:
|
|
|
|
MF.getInfo<X86FunctionInfo>()->setDecorationStyle(StdCall);
|
|
|
|
return LowerStdCallCCArguments(Op, DAG);
|
|
|
|
case CallingConv::X86_FastCall:
|
|
|
|
MF.getInfo<X86FunctionInfo>()->setDecorationStyle(FastCall);
|
|
|
|
return LowerFastCallCCArguments(Op, DAG);
|
|
|
|
default:
|
|
|
|
assert(0 && "Unsupported calling convention");
|
|
|
|
}
|
2006-04-26 09:20:17 +08:00
|
|
|
}
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand X86TargetLowering::LowerMEMSET(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand InFlag(0, 0);
|
|
|
|
SDOperand Chain = Op.getOperand(0);
|
|
|
|
unsigned Align =
|
|
|
|
(unsigned)cast<ConstantSDNode>(Op.getOperand(4))->getValue();
|
|
|
|
if (Align == 0) Align = 1;
|
|
|
|
|
|
|
|
ConstantSDNode *I = dyn_cast<ConstantSDNode>(Op.getOperand(3));
|
|
|
|
// If not DWORD aligned, call memset if size is less than the threshold.
|
|
|
|
// It knows how to align to the right boundary first.
|
|
|
|
if ((Align & 3) != 0 ||
|
|
|
|
(I && I->getValue() < Subtarget->getMinRepStrSizeThreshold())) {
|
|
|
|
MVT::ValueType IntPtr = getPointerTy();
|
2006-05-03 09:29:57 +08:00
|
|
|
const Type *IntPtrTy = getTargetData()->getIntPtrType();
|
2006-04-26 04:13:52 +08:00
|
|
|
std::vector<std::pair<SDOperand, const Type*> > Args;
|
|
|
|
Args.push_back(std::make_pair(Op.getOperand(1), IntPtrTy));
|
|
|
|
// Extend the ubyte argument to be an int value for the call.
|
|
|
|
SDOperand Val = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, Op.getOperand(2));
|
|
|
|
Args.push_back(std::make_pair(Val, IntPtrTy));
|
|
|
|
Args.push_back(std::make_pair(Op.getOperand(3), IntPtrTy));
|
|
|
|
std::pair<SDOperand,SDOperand> CallResult =
|
|
|
|
LowerCallTo(Chain, Type::VoidTy, false, CallingConv::C, false,
|
|
|
|
DAG.getExternalSymbol("memset", IntPtr), Args, DAG);
|
|
|
|
return CallResult.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
MVT::ValueType AVT;
|
|
|
|
SDOperand Count;
|
|
|
|
ConstantSDNode *ValC = dyn_cast<ConstantSDNode>(Op.getOperand(2));
|
|
|
|
unsigned BytesLeft = 0;
|
|
|
|
bool TwoRepStos = false;
|
|
|
|
if (ValC) {
|
|
|
|
unsigned ValReg;
|
2006-09-08 14:48:29 +08:00
|
|
|
uint64_t Val = ValC->getValue() & 255;
|
2006-04-26 04:13:52 +08:00
|
|
|
|
|
|
|
// If the value is a constant, then we can potentially use larger sets.
|
|
|
|
switch (Align & 3) {
|
|
|
|
case 2: // WORD aligned
|
|
|
|
AVT = MVT::i16;
|
|
|
|
ValReg = X86::AX;
|
2006-09-08 14:48:29 +08:00
|
|
|
Val = (Val << 8) | Val;
|
2006-04-26 04:13:52 +08:00
|
|
|
break;
|
2006-09-08 14:48:29 +08:00
|
|
|
case 0: // DWORD aligned
|
2006-04-26 04:13:52 +08:00
|
|
|
AVT = MVT::i32;
|
2006-09-08 14:48:29 +08:00
|
|
|
ValReg = X86::EAX;
|
2006-04-26 04:13:52 +08:00
|
|
|
Val = (Val << 8) | Val;
|
|
|
|
Val = (Val << 16) | Val;
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit() && ((Align & 0xF) == 0)) { // QWORD aligned
|
|
|
|
AVT = MVT::i64;
|
|
|
|
ValReg = X86::RAX;
|
|
|
|
Val = (Val << 32) | Val;
|
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
break;
|
|
|
|
default: // Byte aligned
|
|
|
|
AVT = MVT::i8;
|
|
|
|
ValReg = X86::AL;
|
2006-09-08 14:48:29 +08:00
|
|
|
Count = Op.getOperand(3);
|
2006-04-26 04:13:52 +08:00
|
|
|
break;
|
2006-04-20 06:48:17 +08:00
|
|
|
}
|
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
if (AVT > MVT::i8) {
|
|
|
|
if (I) {
|
|
|
|
unsigned UBytes = MVT::getSizeInBits(AVT) / 8;
|
|
|
|
Count = DAG.getConstant(I->getValue() / UBytes, getPointerTy());
|
|
|
|
BytesLeft = I->getValue() % UBytes;
|
|
|
|
} else {
|
|
|
|
assert(AVT >= MVT::i32 &&
|
|
|
|
"Do not use rep;stos if not at least DWORD aligned");
|
|
|
|
Count = DAG.getNode(ISD::SRL, Op.getOperand(3).getValueType(),
|
|
|
|
Op.getOperand(3), DAG.getConstant(2, MVT::i8));
|
|
|
|
TwoRepStos = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, ValReg, DAG.getConstant(Val, AVT),
|
|
|
|
InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
} else {
|
|
|
|
AVT = MVT::i8;
|
|
|
|
Count = Op.getOperand(3);
|
|
|
|
Chain = DAG.getCopyToReg(Chain, X86::AL, Op.getOperand(2), InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
2006-03-22 10:53:00 +08:00
|
|
|
}
|
2006-03-27 15:00:16 +08:00
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RCX : X86::ECX,
|
|
|
|
Count, InFlag);
|
2006-04-26 04:13:52 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2006-09-08 14:48:29 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RDI : X86::EDI,
|
|
|
|
Op.getOperand(1), InFlag);
|
2006-04-26 04:13:52 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2006-04-25 06:58:52 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(DAG.getValueType(AVT));
|
|
|
|
Ops.push_back(InFlag);
|
2006-08-11 15:35:45 +08:00
|
|
|
Chain = DAG.getNode(X86ISD::REP_STOS, Tys, &Ops[0], Ops.size());
|
Revamp build_vector lowering to take advantage of movss and movd instructions.
movd always clear the top 96 bits and movss does so when it's loading the
value from memory.
The net result is codegen for 4-wide shuffles is much improved. It is near
optimal if one or more elements is a zero. e.g.
__m128i test(int a, int b) {
return _mm_set_epi32(0, 0, b, a);
}
compiles to
_test:
movd 8(%esp), %xmm1
movd 4(%esp), %xmm0
punpckldq %xmm1, %xmm0
ret
compare to gcc:
_test:
subl $12, %esp
movd 20(%esp), %xmm0
movd 16(%esp), %xmm1
punpckldq %xmm0, %xmm1
movq %xmm1, %xmm0
movhps LC0, %xmm0
addl $12, %esp
ret
or icc:
_test:
movd 4(%esp), %xmm0 #5.10
movd 8(%esp), %xmm3 #5.10
xorl %eax, %eax #5.10
movd %eax, %xmm1 #5.10
punpckldq %xmm1, %xmm0 #5.10
movd %eax, %xmm2 #5.10
punpckldq %xmm2, %xmm3 #5.10
punpckldq %xmm3, %xmm0 #5.10
ret #5.10
There are still room for improvement, for example the FP variant of the above example:
__m128 test(float a, float b) {
return _mm_set_ps(0.0, 0.0, b, a);
}
_test:
movss 8(%esp), %xmm1
movss 4(%esp), %xmm0
unpcklps %xmm1, %xmm0
xorps %xmm1, %xmm1
movlhps %xmm1, %xmm0
ret
The xorps and movlhps are unnecessary. This will require post legalizer optimization to handle.
llvm-svn: 27939
2006-04-22 07:03:30 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
if (TwoRepStos) {
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
Count = Op.getOperand(3);
|
|
|
|
MVT::ValueType CVT = Count.getValueType();
|
|
|
|
SDOperand Left = DAG.getNode(ISD::AND, CVT, Count,
|
2006-09-08 14:48:29 +08:00
|
|
|
DAG.getConstant((AVT == MVT::i64) ? 7 : 3, CVT));
|
|
|
|
Chain = DAG.getCopyToReg(Chain, (CVT == MVT::i64) ? X86::RCX : X86::ECX,
|
|
|
|
Left, InFlag);
|
2006-04-26 04:13:52 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
Tys.clear();
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(DAG.getValueType(MVT::i8));
|
|
|
|
Ops.push_back(InFlag);
|
2006-08-11 15:35:45 +08:00
|
|
|
Chain = DAG.getNode(X86ISD::REP_STOS, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
} else if (BytesLeft) {
|
2006-09-08 14:48:29 +08:00
|
|
|
// Issue stores for the last 1 - 7 bytes.
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand Value;
|
|
|
|
unsigned Val = ValC->getValue() & 255;
|
|
|
|
unsigned Offset = I->getValue() - BytesLeft;
|
|
|
|
SDOperand DstAddr = Op.getOperand(1);
|
|
|
|
MVT::ValueType AddrVT = DstAddr.getValueType();
|
2006-09-08 14:48:29 +08:00
|
|
|
if (BytesLeft >= 4) {
|
|
|
|
Val = (Val << 8) | Val;
|
|
|
|
Val = (Val << 16) | Val;
|
|
|
|
Value = DAG.getConstant(Val, MVT::i32);
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
|
|
|
|
DAG.getNode(ISD::ADD, AddrVT, DstAddr,
|
|
|
|
DAG.getConstant(Offset, AddrVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
BytesLeft -= 4;
|
|
|
|
Offset += 4;
|
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
if (BytesLeft >= 2) {
|
|
|
|
Value = DAG.getConstant((Val << 8) | Val, MVT::i16);
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
|
|
|
|
DAG.getNode(ISD::ADD, AddrVT, DstAddr,
|
|
|
|
DAG.getConstant(Offset, AddrVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
BytesLeft -= 2;
|
|
|
|
Offset += 2;
|
|
|
|
}
|
|
|
|
if (BytesLeft == 1) {
|
|
|
|
Value = DAG.getConstant(Val, MVT::i8);
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
|
|
|
|
DAG.getNode(ISD::ADD, AddrVT, DstAddr,
|
|
|
|
DAG.getConstant(Offset, AddrVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Chain;
|
|
|
|
}
|
Revamp build_vector lowering to take advantage of movss and movd instructions.
movd always clear the top 96 bits and movss does so when it's loading the
value from memory.
The net result is codegen for 4-wide shuffles is much improved. It is near
optimal if one or more elements is a zero. e.g.
__m128i test(int a, int b) {
return _mm_set_epi32(0, 0, b, a);
}
compiles to
_test:
movd 8(%esp), %xmm1
movd 4(%esp), %xmm0
punpckldq %xmm1, %xmm0
ret
compare to gcc:
_test:
subl $12, %esp
movd 20(%esp), %xmm0
movd 16(%esp), %xmm1
punpckldq %xmm0, %xmm1
movq %xmm1, %xmm0
movhps LC0, %xmm0
addl $12, %esp
ret
or icc:
_test:
movd 4(%esp), %xmm0 #5.10
movd 8(%esp), %xmm3 #5.10
xorl %eax, %eax #5.10
movd %eax, %xmm1 #5.10
punpckldq %xmm1, %xmm0 #5.10
movd %eax, %xmm2 #5.10
punpckldq %xmm2, %xmm3 #5.10
punpckldq %xmm3, %xmm0 #5.10
ret #5.10
There are still room for improvement, for example the FP variant of the above example:
__m128 test(float a, float b) {
return _mm_set_ps(0.0, 0.0, b, a);
}
_test:
movss 8(%esp), %xmm1
movss 4(%esp), %xmm0
unpcklps %xmm1, %xmm0
xorps %xmm1, %xmm1
movlhps %xmm1, %xmm0
ret
The xorps and movlhps are unnecessary. This will require post legalizer optimization to handle.
llvm-svn: 27939
2006-04-22 07:03:30 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand X86TargetLowering::LowerMEMCPY(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
SDOperand Chain = Op.getOperand(0);
|
|
|
|
unsigned Align =
|
|
|
|
(unsigned)cast<ConstantSDNode>(Op.getOperand(4))->getValue();
|
|
|
|
if (Align == 0) Align = 1;
|
|
|
|
|
|
|
|
ConstantSDNode *I = dyn_cast<ConstantSDNode>(Op.getOperand(3));
|
|
|
|
// If not DWORD aligned, call memcpy if size is less than the threshold.
|
|
|
|
// It knows how to align to the right boundary first.
|
|
|
|
if ((Align & 3) != 0 ||
|
|
|
|
(I && I->getValue() < Subtarget->getMinRepStrSizeThreshold())) {
|
|
|
|
MVT::ValueType IntPtr = getPointerTy();
|
2006-05-03 09:29:57 +08:00
|
|
|
const Type *IntPtrTy = getTargetData()->getIntPtrType();
|
2006-04-26 04:13:52 +08:00
|
|
|
std::vector<std::pair<SDOperand, const Type*> > Args;
|
|
|
|
Args.push_back(std::make_pair(Op.getOperand(1), IntPtrTy));
|
|
|
|
Args.push_back(std::make_pair(Op.getOperand(2), IntPtrTy));
|
|
|
|
Args.push_back(std::make_pair(Op.getOperand(3), IntPtrTy));
|
|
|
|
std::pair<SDOperand,SDOperand> CallResult =
|
|
|
|
LowerCallTo(Chain, Type::VoidTy, false, CallingConv::C, false,
|
|
|
|
DAG.getExternalSymbol("memcpy", IntPtr), Args, DAG);
|
|
|
|
return CallResult.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
MVT::ValueType AVT;
|
|
|
|
SDOperand Count;
|
|
|
|
unsigned BytesLeft = 0;
|
|
|
|
bool TwoRepMovs = false;
|
|
|
|
switch (Align & 3) {
|
|
|
|
case 2: // WORD aligned
|
|
|
|
AVT = MVT::i16;
|
|
|
|
break;
|
2006-09-08 14:48:29 +08:00
|
|
|
case 0: // DWORD aligned
|
2006-04-26 04:13:52 +08:00
|
|
|
AVT = MVT::i32;
|
2006-09-08 14:48:29 +08:00
|
|
|
if (Subtarget->is64Bit() && ((Align & 0xF) == 0)) // QWORD aligned
|
|
|
|
AVT = MVT::i64;
|
2006-04-26 04:13:52 +08:00
|
|
|
break;
|
|
|
|
default: // Byte aligned
|
|
|
|
AVT = MVT::i8;
|
|
|
|
Count = Op.getOperand(3);
|
|
|
|
break;
|
|
|
|
}
|
Revamp build_vector lowering to take advantage of movss and movd instructions.
movd always clear the top 96 bits and movss does so when it's loading the
value from memory.
The net result is codegen for 4-wide shuffles is much improved. It is near
optimal if one or more elements is a zero. e.g.
__m128i test(int a, int b) {
return _mm_set_epi32(0, 0, b, a);
}
compiles to
_test:
movd 8(%esp), %xmm1
movd 4(%esp), %xmm0
punpckldq %xmm1, %xmm0
ret
compare to gcc:
_test:
subl $12, %esp
movd 20(%esp), %xmm0
movd 16(%esp), %xmm1
punpckldq %xmm0, %xmm1
movq %xmm1, %xmm0
movhps LC0, %xmm0
addl $12, %esp
ret
or icc:
_test:
movd 4(%esp), %xmm0 #5.10
movd 8(%esp), %xmm3 #5.10
xorl %eax, %eax #5.10
movd %eax, %xmm1 #5.10
punpckldq %xmm1, %xmm0 #5.10
movd %eax, %xmm2 #5.10
punpckldq %xmm2, %xmm3 #5.10
punpckldq %xmm3, %xmm0 #5.10
ret #5.10
There are still room for improvement, for example the FP variant of the above example:
__m128 test(float a, float b) {
return _mm_set_ps(0.0, 0.0, b, a);
}
_test:
movss 8(%esp), %xmm1
movss 4(%esp), %xmm0
unpcklps %xmm1, %xmm0
xorps %xmm1, %xmm1
movlhps %xmm1, %xmm0
ret
The xorps and movlhps are unnecessary. This will require post legalizer optimization to handle.
llvm-svn: 27939
2006-04-22 07:03:30 +08:00
|
|
|
|
2006-09-08 14:48:29 +08:00
|
|
|
if (AVT > MVT::i8) {
|
|
|
|
if (I) {
|
|
|
|
unsigned UBytes = MVT::getSizeInBits(AVT) / 8;
|
|
|
|
Count = DAG.getConstant(I->getValue() / UBytes, getPointerTy());
|
|
|
|
BytesLeft = I->getValue() % UBytes;
|
|
|
|
} else {
|
|
|
|
assert(AVT >= MVT::i32 &&
|
|
|
|
"Do not use rep;movs if not at least DWORD aligned");
|
|
|
|
Count = DAG.getNode(ISD::SRL, Op.getOperand(3).getValueType(),
|
|
|
|
Op.getOperand(3), DAG.getConstant(2, MVT::i8));
|
|
|
|
TwoRepMovs = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand InFlag(0, 0);
|
2006-09-08 14:48:29 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RCX : X86::ECX,
|
|
|
|
Count, InFlag);
|
2006-04-26 04:13:52 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2006-09-08 14:48:29 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RDI : X86::EDI,
|
|
|
|
Op.getOperand(1), InFlag);
|
2006-04-26 04:13:52 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
2006-09-08 14:48:29 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, Subtarget->is64Bit() ? X86::RSI : X86::ESI,
|
|
|
|
Op.getOperand(2), InFlag);
|
2006-04-26 04:13:52 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
Now generating perfect (I think) code for "vector set" with a single non-zero
scalar value.
e.g.
_mm_set_epi32(0, a, 0, 0);
==>
movd 4(%esp), %xmm0
pshufd $69, %xmm0, %xmm0
_mm_set_epi8(0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
==>
movzbw 4(%esp), %ax
movzwl %ax, %eax
pxor %xmm0, %xmm0
pinsrw $5, %eax, %xmm0
llvm-svn: 27923
2006-04-21 09:05:10 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(DAG.getValueType(AVT));
|
|
|
|
Ops.push_back(InFlag);
|
2006-08-11 15:35:45 +08:00
|
|
|
Chain = DAG.getNode(X86ISD::REP_MOVS, Tys, &Ops[0], Ops.size());
|
2006-03-24 15:29:27 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
if (TwoRepMovs) {
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
Count = Op.getOperand(3);
|
|
|
|
MVT::ValueType CVT = Count.getValueType();
|
|
|
|
SDOperand Left = DAG.getNode(ISD::AND, CVT, Count,
|
2006-09-08 14:48:29 +08:00
|
|
|
DAG.getConstant((AVT == MVT::i64) ? 7 : 3, CVT));
|
|
|
|
Chain = DAG.getCopyToReg(Chain, (CVT == MVT::i64) ? X86::RCX : X86::ECX,
|
|
|
|
Left, InFlag);
|
2006-04-26 04:13:52 +08:00
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
Tys.clear();
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(DAG.getValueType(MVT::i8));
|
|
|
|
Ops.push_back(InFlag);
|
2006-08-11 15:35:45 +08:00
|
|
|
Chain = DAG.getNode(X86ISD::REP_MOVS, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
} else if (BytesLeft) {
|
2006-09-08 14:48:29 +08:00
|
|
|
// Issue loads and stores for the last 1 - 7 bytes.
|
2006-04-26 04:13:52 +08:00
|
|
|
unsigned Offset = I->getValue() - BytesLeft;
|
|
|
|
SDOperand DstAddr = Op.getOperand(1);
|
|
|
|
MVT::ValueType DstVT = DstAddr.getValueType();
|
|
|
|
SDOperand SrcAddr = Op.getOperand(2);
|
|
|
|
MVT::ValueType SrcVT = SrcAddr.getValueType();
|
|
|
|
SDOperand Value;
|
2006-09-08 14:48:29 +08:00
|
|
|
if (BytesLeft >= 4) {
|
|
|
|
Value = DAG.getLoad(MVT::i32, Chain,
|
|
|
|
DAG.getNode(ISD::ADD, SrcVT, SrcAddr,
|
|
|
|
DAG.getConstant(Offset, SrcVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
Chain = Value.getValue(1);
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
|
|
|
|
DAG.getNode(ISD::ADD, DstVT, DstAddr,
|
|
|
|
DAG.getConstant(Offset, DstVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
BytesLeft -= 4;
|
|
|
|
Offset += 4;
|
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
if (BytesLeft >= 2) {
|
|
|
|
Value = DAG.getLoad(MVT::i16, Chain,
|
|
|
|
DAG.getNode(ISD::ADD, SrcVT, SrcAddr,
|
|
|
|
DAG.getConstant(Offset, SrcVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
Chain = Value.getValue(1);
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
|
|
|
|
DAG.getNode(ISD::ADD, DstVT, DstAddr,
|
|
|
|
DAG.getConstant(Offset, DstVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
BytesLeft -= 2;
|
|
|
|
Offset += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BytesLeft == 1) {
|
|
|
|
Value = DAG.getLoad(MVT::i8, Chain,
|
|
|
|
DAG.getNode(ISD::ADD, SrcVT, SrcAddr,
|
|
|
|
DAG.getConstant(Offset, SrcVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
|
|
|
Chain = Value.getValue(1);
|
|
|
|
Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Value,
|
|
|
|
DAG.getNode(ISD::ADD, DstVT, DstAddr,
|
|
|
|
DAG.getConstant(Offset, DstVT)),
|
|
|
|
DAG.getSrcValue(NULL));
|
2006-03-25 17:37:23 +08:00
|
|
|
}
|
2006-03-24 15:29:27 +08:00
|
|
|
}
|
2006-04-01 03:22:53 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
return Chain;
|
|
|
|
}
|
2006-04-01 03:22:53 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerREADCYCLCECOUNTER(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
Tys.push_back(MVT::Flag);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op.getOperand(0));
|
2006-08-11 15:35:45 +08:00
|
|
|
SDOperand rd = DAG.getNode(X86ISD::RDTSC_DAG, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
Ops.clear();
|
|
|
|
Ops.push_back(DAG.getCopyFromReg(rd, X86::EAX, MVT::i32, rd.getValue(1)));
|
|
|
|
Ops.push_back(DAG.getCopyFromReg(Ops[0].getValue(1), X86::EDX,
|
|
|
|
MVT::i32, Ops[0].getValue(2)));
|
|
|
|
Ops.push_back(Ops[1].getValue(1));
|
|
|
|
Tys[0] = Tys[1] = MVT::i32;
|
|
|
|
Tys.push_back(MVT::Other);
|
2006-08-11 15:35:45 +08:00
|
|
|
return DAG.getNode(ISD::MERGE_VALUES, Tys, &Ops[0], Ops.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::LowerVASTART(SDOperand Op, SelectionDAG &DAG) {
|
2006-09-08 14:48:29 +08:00
|
|
|
if (!Subtarget->is64Bit()) {
|
|
|
|
// vastart just stores the address of the VarArgsFrameIndex slot into the
|
|
|
|
// memory location argument.
|
|
|
|
SDOperand FR = DAG.getFrameIndex(VarArgsFrameIndex, getPointerTy());
|
|
|
|
return DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0), FR,
|
|
|
|
Op.getOperand(1), Op.getOperand(2));
|
|
|
|
}
|
|
|
|
|
|
|
|
// __va_list_tag:
|
|
|
|
// gp_offset (0 - 6 * 8)
|
|
|
|
// fp_offset (48 - 48 + 8 * 16)
|
|
|
|
// overflow_arg_area (point to parameters coming in memory).
|
|
|
|
// reg_save_area
|
|
|
|
std::vector<SDOperand> MemOps;
|
|
|
|
SDOperand FIN = Op.getOperand(1);
|
|
|
|
// Store gp_offset
|
|
|
|
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
|
|
|
|
DAG.getConstant(VarArgsGPOffset, MVT::i32),
|
|
|
|
FIN, Op.getOperand(2));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
|
|
|
|
// Store fp_offset
|
|
|
|
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
|
|
|
|
DAG.getConstant(4, getPointerTy()));
|
|
|
|
Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
|
|
|
|
DAG.getConstant(VarArgsFPOffset, MVT::i32),
|
|
|
|
FIN, Op.getOperand(2));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
|
|
|
|
// Store ptr to overflow_arg_area
|
|
|
|
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
|
|
|
|
DAG.getConstant(4, getPointerTy()));
|
|
|
|
SDOperand OVFIN = DAG.getFrameIndex(VarArgsFrameIndex, getPointerTy());
|
|
|
|
Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
|
|
|
|
OVFIN, FIN, Op.getOperand(2));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
|
|
|
|
// Store ptr to reg_save_area.
|
|
|
|
FIN = DAG.getNode(ISD::ADD, getPointerTy(), FIN,
|
|
|
|
DAG.getConstant(8, getPointerTy()));
|
|
|
|
SDOperand RSFIN = DAG.getFrameIndex(RegSaveFrameIndex, getPointerTy());
|
|
|
|
Store = DAG.getNode(ISD::STORE, MVT::Other, Op.getOperand(0),
|
|
|
|
RSFIN, FIN, Op.getOperand(2));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
return DAG.getNode(ISD::TokenFactor, MVT::Other, &MemOps[0], MemOps.size());
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand
|
|
|
|
X86TargetLowering::LowerINTRINSIC_WO_CHAIN(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getValue();
|
|
|
|
switch (IntNo) {
|
|
|
|
default: return SDOperand(); // Don't custom lower most intrinsics.
|
2006-04-06 07:38:46 +08:00
|
|
|
// Comparison intrinsics.
|
2006-04-26 04:13:52 +08:00
|
|
|
case Intrinsic::x86_sse_comieq_ss:
|
|
|
|
case Intrinsic::x86_sse_comilt_ss:
|
|
|
|
case Intrinsic::x86_sse_comile_ss:
|
|
|
|
case Intrinsic::x86_sse_comigt_ss:
|
|
|
|
case Intrinsic::x86_sse_comige_ss:
|
|
|
|
case Intrinsic::x86_sse_comineq_ss:
|
|
|
|
case Intrinsic::x86_sse_ucomieq_ss:
|
|
|
|
case Intrinsic::x86_sse_ucomilt_ss:
|
|
|
|
case Intrinsic::x86_sse_ucomile_ss:
|
|
|
|
case Intrinsic::x86_sse_ucomigt_ss:
|
|
|
|
case Intrinsic::x86_sse_ucomige_ss:
|
|
|
|
case Intrinsic::x86_sse_ucomineq_ss:
|
|
|
|
case Intrinsic::x86_sse2_comieq_sd:
|
|
|
|
case Intrinsic::x86_sse2_comilt_sd:
|
|
|
|
case Intrinsic::x86_sse2_comile_sd:
|
|
|
|
case Intrinsic::x86_sse2_comigt_sd:
|
|
|
|
case Intrinsic::x86_sse2_comige_sd:
|
|
|
|
case Intrinsic::x86_sse2_comineq_sd:
|
|
|
|
case Intrinsic::x86_sse2_ucomieq_sd:
|
|
|
|
case Intrinsic::x86_sse2_ucomilt_sd:
|
|
|
|
case Intrinsic::x86_sse2_ucomile_sd:
|
|
|
|
case Intrinsic::x86_sse2_ucomigt_sd:
|
|
|
|
case Intrinsic::x86_sse2_ucomige_sd:
|
|
|
|
case Intrinsic::x86_sse2_ucomineq_sd: {
|
|
|
|
unsigned Opc = 0;
|
|
|
|
ISD::CondCode CC = ISD::SETCC_INVALID;
|
|
|
|
switch (IntNo) {
|
|
|
|
default: break;
|
|
|
|
case Intrinsic::x86_sse_comieq_ss:
|
|
|
|
case Intrinsic::x86_sse2_comieq_sd:
|
|
|
|
Opc = X86ISD::COMI;
|
|
|
|
CC = ISD::SETEQ;
|
|
|
|
break;
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse_comilt_ss:
|
|
|
|
case Intrinsic::x86_sse2_comilt_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::COMI;
|
|
|
|
CC = ISD::SETLT;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_comile_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_comile_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::COMI;
|
|
|
|
CC = ISD::SETLE;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_comigt_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_comigt_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::COMI;
|
|
|
|
CC = ISD::SETGT;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_comige_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_comige_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::COMI;
|
|
|
|
CC = ISD::SETGE;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_comineq_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_comineq_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::COMI;
|
|
|
|
CC = ISD::SETNE;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_ucomieq_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_ucomieq_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::UCOMI;
|
|
|
|
CC = ISD::SETEQ;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_ucomilt_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_ucomilt_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::UCOMI;
|
|
|
|
CC = ISD::SETLT;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_ucomile_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_ucomile_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::UCOMI;
|
|
|
|
CC = ISD::SETLE;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_ucomigt_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_ucomigt_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::UCOMI;
|
|
|
|
CC = ISD::SETGT;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_ucomige_ss:
|
2006-04-06 07:38:46 +08:00
|
|
|
case Intrinsic::x86_sse2_ucomige_sd:
|
2006-04-26 04:13:52 +08:00
|
|
|
Opc = X86ISD::UCOMI;
|
|
|
|
CC = ISD::SETGE;
|
|
|
|
break;
|
|
|
|
case Intrinsic::x86_sse_ucomineq_ss:
|
|
|
|
case Intrinsic::x86_sse2_ucomineq_sd:
|
|
|
|
Opc = X86ISD::UCOMI;
|
|
|
|
CC = ISD::SETNE;
|
|
|
|
break;
|
2006-04-06 07:38:46 +08:00
|
|
|
}
|
2006-09-11 10:19:56 +08:00
|
|
|
|
2006-04-26 04:13:52 +08:00
|
|
|
unsigned X86CC;
|
2006-09-13 11:22:10 +08:00
|
|
|
SDOperand LHS = Op.getOperand(1);
|
|
|
|
SDOperand RHS = Op.getOperand(2);
|
|
|
|
translateX86CC(CC, true, X86CC, LHS, RHS, DAG);
|
2006-09-11 10:19:56 +08:00
|
|
|
|
|
|
|
const MVT::ValueType *VTs = DAG.getNodeValueTypes(MVT::Other, MVT::Flag);
|
2006-09-13 11:22:10 +08:00
|
|
|
SDOperand Ops1[] = { DAG.getEntryNode(), LHS, RHS };
|
2006-09-11 10:19:56 +08:00
|
|
|
SDOperand Cond = DAG.getNode(Opc, VTs, 2, Ops1, 3);
|
|
|
|
VTs = DAG.getNodeValueTypes(MVT::i8, MVT::Flag);
|
|
|
|
SDOperand Ops2[] = { DAG.getConstant(X86CC, MVT::i8), Cond };
|
|
|
|
SDOperand SetCC = DAG.getNode(X86ISD::SETCC, VTs, 2, Ops2, 2);
|
2006-04-26 04:13:52 +08:00
|
|
|
return DAG.getNode(ISD::ANY_EXTEND, MVT::i32, SetCC);
|
|
|
|
}
|
2006-04-06 07:38:46 +08:00
|
|
|
}
|
2006-04-26 04:13:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// LowerOperation - Provide custom lowering hooks for some operations.
|
|
|
|
///
|
|
|
|
SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
|
|
|
|
switch (Op.getOpcode()) {
|
|
|
|
default: assert(0 && "Should not custom lower this!");
|
|
|
|
case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG);
|
|
|
|
case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG);
|
|
|
|
case ISD::EXTRACT_VECTOR_ELT: return LowerEXTRACT_VECTOR_ELT(Op, DAG);
|
|
|
|
case ISD::INSERT_VECTOR_ELT: return LowerINSERT_VECTOR_ELT(Op, DAG);
|
|
|
|
case ISD::SCALAR_TO_VECTOR: return LowerSCALAR_TO_VECTOR(Op, DAG);
|
|
|
|
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
|
|
|
|
case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
|
|
|
|
case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG);
|
|
|
|
case ISD::SHL_PARTS:
|
|
|
|
case ISD::SRA_PARTS:
|
|
|
|
case ISD::SRL_PARTS: return LowerShift(Op, DAG);
|
|
|
|
case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG);
|
|
|
|
case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG);
|
|
|
|
case ISD::FABS: return LowerFABS(Op, DAG);
|
|
|
|
case ISD::FNEG: return LowerFNEG(Op, DAG);
|
2006-09-11 10:19:56 +08:00
|
|
|
case ISD::SETCC: return LowerSETCC(Op, DAG, DAG.getEntryNode());
|
2006-04-26 04:13:52 +08:00
|
|
|
case ISD::SELECT: return LowerSELECT(Op, DAG);
|
|
|
|
case ISD::BRCOND: return LowerBRCOND(Op, DAG);
|
|
|
|
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
|
2006-05-25 08:59:30 +08:00
|
|
|
case ISD::CALL: return LowerCALL(Op, DAG);
|
2006-04-26 04:13:52 +08:00
|
|
|
case ISD::RET: return LowerRET(Op, DAG);
|
2006-04-26 09:20:17 +08:00
|
|
|
case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG);
|
2006-04-26 04:13:52 +08:00
|
|
|
case ISD::MEMSET: return LowerMEMSET(Op, DAG);
|
|
|
|
case ISD::MEMCPY: return LowerMEMCPY(Op, DAG);
|
|
|
|
case ISD::READCYCLECOUNTER: return LowerREADCYCLCECOUNTER(Op, DAG);
|
|
|
|
case ISD::VASTART: return LowerVASTART(Op, DAG);
|
|
|
|
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
2005-12-23 15:31:11 +08:00
|
|
|
}
|
2005-11-15 08:40:23 +08:00
|
|
|
}
|
2005-12-20 14:22:03 +08:00
|
|
|
|
|
|
|
const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|
|
|
switch (Opcode) {
|
|
|
|
default: return NULL;
|
2006-01-10 02:33:28 +08:00
|
|
|
case X86ISD::SHLD: return "X86ISD::SHLD";
|
|
|
|
case X86ISD::SHRD: return "X86ISD::SHRD";
|
2006-01-31 11:14:29 +08:00
|
|
|
case X86ISD::FAND: return "X86ISD::FAND";
|
2006-02-01 06:28:30 +08:00
|
|
|
case X86ISD::FXOR: return "X86ISD::FXOR";
|
2006-01-13 06:54:21 +08:00
|
|
|
case X86ISD::FILD: return "X86ISD::FILD";
|
2006-02-04 10:20:30 +08:00
|
|
|
case X86ISD::FILD_FLAG: return "X86ISD::FILD_FLAG";
|
2005-12-20 14:22:03 +08:00
|
|
|
case X86ISD::FP_TO_INT16_IN_MEM: return "X86ISD::FP_TO_INT16_IN_MEM";
|
|
|
|
case X86ISD::FP_TO_INT32_IN_MEM: return "X86ISD::FP_TO_INT32_IN_MEM";
|
|
|
|
case X86ISD::FP_TO_INT64_IN_MEM: return "X86ISD::FP_TO_INT64_IN_MEM";
|
2005-12-21 10:39:21 +08:00
|
|
|
case X86ISD::FLD: return "X86ISD::FLD";
|
2006-01-05 08:27:02 +08:00
|
|
|
case X86ISD::FST: return "X86ISD::FST";
|
|
|
|
case X86ISD::FP_GET_RESULT: return "X86ISD::FP_GET_RESULT";
|
2005-12-21 10:39:21 +08:00
|
|
|
case X86ISD::FP_SET_RESULT: return "X86ISD::FP_SET_RESULT";
|
2005-12-20 14:22:03 +08:00
|
|
|
case X86ISD::CALL: return "X86ISD::CALL";
|
|
|
|
case X86ISD::TAILCALL: return "X86ISD::TAILCALL";
|
|
|
|
case X86ISD::RDTSC_DAG: return "X86ISD::RDTSC_DAG";
|
|
|
|
case X86ISD::CMP: return "X86ISD::CMP";
|
2006-04-06 07:38:46 +08:00
|
|
|
case X86ISD::COMI: return "X86ISD::COMI";
|
|
|
|
case X86ISD::UCOMI: return "X86ISD::UCOMI";
|
2005-12-22 04:21:51 +08:00
|
|
|
case X86ISD::SETCC: return "X86ISD::SETCC";
|
2005-12-20 14:22:03 +08:00
|
|
|
case X86ISD::CMOV: return "X86ISD::CMOV";
|
|
|
|
case X86ISD::BRCOND: return "X86ISD::BRCOND";
|
2005-12-21 10:39:21 +08:00
|
|
|
case X86ISD::RET_FLAG: return "X86ISD::RET_FLAG";
|
2006-03-04 09:12:00 +08:00
|
|
|
case X86ISD::REP_STOS: return "X86ISD::REP_STOS";
|
|
|
|
case X86ISD::REP_MOVS: return "X86ISD::REP_MOVS";
|
2006-02-01 06:28:30 +08:00
|
|
|
case X86ISD::LOAD_PACK: return "X86ISD::LOAD_PACK";
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
case X86ISD::LOAD_UA: return "X86ISD::LOAD_UA";
|
2006-02-18 08:15:05 +08:00
|
|
|
case X86ISD::GlobalBaseReg: return "X86ISD::GlobalBaseReg";
|
2006-02-24 04:41:18 +08:00
|
|
|
case X86ISD::Wrapper: return "X86ISD::Wrapper";
|
2006-03-25 07:15:12 +08:00
|
|
|
case X86ISD::S2VEC: return "X86ISD::S2VEC";
|
2006-04-01 03:22:53 +08:00
|
|
|
case X86ISD::PEXTRW: return "X86ISD::PEXTRW";
|
2006-04-01 05:55:24 +08:00
|
|
|
case X86ISD::PINSRW: return "X86ISD::PINSRW";
|
2005-12-20 14:22:03 +08:00
|
|
|
}
|
|
|
|
}
|
2005-12-22 07:05:39 +08:00
|
|
|
|
2006-07-06 06:17:51 +08:00
|
|
|
/// isLegalAddressImmediate - Return true if the integer value or
|
|
|
|
/// GlobalValue can be used as the offset of the target addressing mode.
|
|
|
|
bool X86TargetLowering::isLegalAddressImmediate(int64_t V) const {
|
|
|
|
// X86 allows a sign-extended 32-bit immediate field.
|
|
|
|
return (V > -(1LL << 32) && V < (1LL << 32)-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool X86TargetLowering::isLegalAddressImmediate(GlobalValue *GV) const {
|
|
|
|
// GV is 64-bit but displacement field is 32-bit unless we are in small code
|
|
|
|
// model. Mac OS X happens to support only small PIC code model.
|
|
|
|
// FIXME: better support for other OS's.
|
|
|
|
if (Subtarget->is64Bit() && !Subtarget->isTargetDarwin())
|
|
|
|
return false;
|
|
|
|
if (Subtarget->isTargetDarwin()) {
|
|
|
|
Reloc::Model RModel = getTargetMachine().getRelocationModel();
|
|
|
|
if (RModel == Reloc::Static)
|
|
|
|
return true;
|
|
|
|
else if (RModel == Reloc::DynamicNoPIC)
|
|
|
|
return !DarwinGVRequiresExtraLoad(GV);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
} else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isShuffleMaskLegal - Targets can use this to indicate that they only
|
|
|
|
/// support *some* VECTOR_SHUFFLE operations, those with specific masks.
|
|
|
|
/// By default, if a target supports the VECTOR_SHUFFLE node, all mask values
|
|
|
|
/// are assumed to be legal.
|
|
|
|
bool
|
|
|
|
X86TargetLowering::isShuffleMaskLegal(SDOperand Mask, MVT::ValueType VT) const {
|
|
|
|
// Only do shuffles on 128-bit vector types for now.
|
|
|
|
if (MVT::getSizeInBits(VT) == 64) return false;
|
|
|
|
return (Mask.Val->getNumOperands() <= 4 ||
|
|
|
|
isSplatMask(Mask.Val) ||
|
|
|
|
isPSHUFHW_PSHUFLWMask(Mask.Val) ||
|
|
|
|
X86::isUNPCKLMask(Mask.Val) ||
|
|
|
|
X86::isUNPCKL_v_undef_Mask(Mask.Val) ||
|
|
|
|
X86::isUNPCKHMask(Mask.Val));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool X86TargetLowering::isVectorClearMaskLegal(std::vector<SDOperand> &BVOps,
|
|
|
|
MVT::ValueType EVT,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
unsigned NumElts = BVOps.size();
|
|
|
|
// Only do shuffles on 128-bit vector types for now.
|
|
|
|
if (MVT::getSizeInBits(EVT) * NumElts == 64) return false;
|
|
|
|
if (NumElts == 2) return true;
|
|
|
|
if (NumElts == 4) {
|
|
|
|
return (isMOVLMask(BVOps) || isCommutedMOVL(BVOps, true) ||
|
|
|
|
isSHUFPMask(BVOps) || isCommutedSHUFP(BVOps));
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// X86 Scheduler Hooks
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
MachineBasicBlock *
|
|
|
|
X86TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
|
|
|
|
MachineBasicBlock *BB) {
|
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: assert(false && "Unexpected instr type to insert");
|
|
|
|
case X86::CMOV_FR32:
|
|
|
|
case X86::CMOV_FR64:
|
|
|
|
case X86::CMOV_V4F32:
|
|
|
|
case X86::CMOV_V2F64:
|
|
|
|
case X86::CMOV_V2I64: {
|
|
|
|
// To "insert" a SELECT_CC instruction, we actually have to insert the
|
|
|
|
// diamond control-flow pattern. The incoming instruction knows the
|
|
|
|
// destination vreg to set, the condition code register to branch on, the
|
|
|
|
// true/false values to select between, and a branch opcode to use.
|
|
|
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
|
|
|
ilist<MachineBasicBlock>::iterator It = BB;
|
|
|
|
++It;
|
|
|
|
|
|
|
|
// thisMBB:
|
|
|
|
// ...
|
|
|
|
// TrueVal = ...
|
|
|
|
// cmpTY ccX, r1, r2
|
|
|
|
// bCC copy1MBB
|
|
|
|
// fallthrough --> copy0MBB
|
|
|
|
MachineBasicBlock *thisMBB = BB;
|
|
|
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
|
|
|
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
|
|
|
unsigned Opc = getCondBrOpcodeForX86CC(MI->getOperand(3).getImmedValue());
|
|
|
|
BuildMI(BB, Opc, 1).addMBB(sinkMBB);
|
|
|
|
MachineFunction *F = BB->getParent();
|
|
|
|
F->getBasicBlockList().insert(It, copy0MBB);
|
|
|
|
F->getBasicBlockList().insert(It, sinkMBB);
|
|
|
|
// Update machine-CFG edges by first adding all successors of the current
|
|
|
|
// block to the new block which will contain the Phi node for the select.
|
|
|
|
for(MachineBasicBlock::succ_iterator i = BB->succ_begin(),
|
|
|
|
e = BB->succ_end(); i != e; ++i)
|
|
|
|
sinkMBB->addSuccessor(*i);
|
|
|
|
// Next, remove all successors of the current block, and add the true
|
|
|
|
// and fallthrough blocks as its successors.
|
|
|
|
while(!BB->succ_empty())
|
|
|
|
BB->removeSuccessor(BB->succ_begin());
|
|
|
|
BB->addSuccessor(copy0MBB);
|
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
|
|
|
// copy0MBB:
|
|
|
|
// %FalseValue = ...
|
|
|
|
// # fallthrough to sinkMBB
|
|
|
|
BB = copy0MBB;
|
|
|
|
|
|
|
|
// Update machine-CFG edges
|
|
|
|
BB->addSuccessor(sinkMBB);
|
|
|
|
|
|
|
|
// sinkMBB:
|
|
|
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
|
|
|
// ...
|
|
|
|
BB = sinkMBB;
|
|
|
|
BuildMI(BB, X86::PHI, 4, MI->getOperand(0).getReg())
|
|
|
|
.addReg(MI->getOperand(1).getReg()).addMBB(copy0MBB)
|
|
|
|
.addReg(MI->getOperand(2).getReg()).addMBB(thisMBB);
|
|
|
|
|
|
|
|
delete MI; // The pseudo instruction is gone now.
|
|
|
|
return BB;
|
|
|
|
}
|
|
|
|
|
|
|
|
case X86::FP_TO_INT16_IN_MEM:
|
|
|
|
case X86::FP_TO_INT32_IN_MEM:
|
|
|
|
case X86::FP_TO_INT64_IN_MEM: {
|
|
|
|
// 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 OldCW =
|
|
|
|
F->getSSARegMap()->createVirtualRegister(X86::GR16RegisterClass);
|
|
|
|
addFrameReference(BuildMI(BB, X86::MOV16rm, 4, OldCW), CWFrameIdx);
|
|
|
|
|
|
|
|
// Set the high part to be round to zero...
|
|
|
|
addFrameReference(BuildMI(BB, X86::MOV16mi, 5), CWFrameIdx).addImm(0xC7F);
|
|
|
|
|
|
|
|
// 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::MOV16mr, 5), CWFrameIdx).addReg(OldCW);
|
|
|
|
|
|
|
|
// Get the X86 opcode to use.
|
|
|
|
unsigned Opc;
|
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: assert(0 && "illegal opcode!");
|
|
|
|
case X86::FP_TO_INT16_IN_MEM: Opc = X86::FpIST16m; break;
|
|
|
|
case X86::FP_TO_INT32_IN_MEM: Opc = X86::FpIST32m; break;
|
|
|
|
case X86::FP_TO_INT64_IN_MEM: Opc = X86::FpIST64m; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
X86AddressMode AM;
|
|
|
|
MachineOperand &Op = MI->getOperand(0);
|
|
|
|
if (Op.isRegister()) {
|
|
|
|
AM.BaseType = X86AddressMode::RegBase;
|
|
|
|
AM.Base.Reg = Op.getReg();
|
|
|
|
} else {
|
|
|
|
AM.BaseType = X86AddressMode::FrameIndexBase;
|
|
|
|
AM.Base.FrameIndex = Op.getFrameIndex();
|
|
|
|
}
|
|
|
|
Op = MI->getOperand(1);
|
|
|
|
if (Op.isImmediate())
|
|
|
|
AM.Scale = Op.getImmedValue();
|
|
|
|
Op = MI->getOperand(2);
|
|
|
|
if (Op.isImmediate())
|
|
|
|
AM.IndexReg = Op.getImmedValue();
|
|
|
|
Op = MI->getOperand(3);
|
|
|
|
if (Op.isGlobalAddress()) {
|
|
|
|
AM.GV = Op.getGlobal();
|
|
|
|
} else {
|
|
|
|
AM.Disp = Op.getImmedValue();
|
|
|
|
}
|
|
|
|
addFullAddress(BuildMI(BB, Opc, 5), AM).addReg(MI->getOperand(4).getReg());
|
|
|
|
|
|
|
|
// Reload the original control word now.
|
|
|
|
addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);
|
|
|
|
|
|
|
|
delete MI; // The pseudo instruction is gone now.
|
|
|
|
return BB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// X86 Optimization Hooks
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-02-17 05:11:51 +08:00
|
|
|
void X86TargetLowering::computeMaskedBitsForTargetNode(const SDOperand Op,
|
|
|
|
uint64_t Mask,
|
|
|
|
uint64_t &KnownZero,
|
|
|
|
uint64_t &KnownOne,
|
|
|
|
unsigned Depth) const {
|
2005-12-22 07:05:39 +08:00
|
|
|
unsigned Opc = Op.getOpcode();
|
2006-04-05 14:11:20 +08:00
|
|
|
assert((Opc >= ISD::BUILTIN_OP_END ||
|
|
|
|
Opc == ISD::INTRINSIC_WO_CHAIN ||
|
|
|
|
Opc == ISD::INTRINSIC_W_CHAIN ||
|
|
|
|
Opc == ISD::INTRINSIC_VOID) &&
|
|
|
|
"Should use MaskedValueIsZero if you don't know whether Op"
|
|
|
|
" is a target node!");
|
2005-12-22 07:05:39 +08:00
|
|
|
|
2006-04-05 14:11:20 +08:00
|
|
|
KnownZero = KnownOne = 0; // Don't know anything.
|
2005-12-22 07:05:39 +08:00
|
|
|
switch (Opc) {
|
2006-04-05 14:11:20 +08:00
|
|
|
default: break;
|
2006-02-17 05:11:51 +08:00
|
|
|
case X86ISD::SETCC:
|
|
|
|
KnownZero |= (MVT::getIntVTBitMask(Op.getValueType()) ^ 1ULL);
|
|
|
|
break;
|
2005-12-22 07:05:39 +08:00
|
|
|
}
|
|
|
|
}
|
2006-02-01 03:43:35 +08:00
|
|
|
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
/// getShuffleScalarElt - Returns the scalar element that will make up the ith
|
|
|
|
/// element of the result of the vector shuffle.
|
|
|
|
static SDOperand getShuffleScalarElt(SDNode *N, unsigned i, SelectionDAG &DAG) {
|
|
|
|
MVT::ValueType VT = N->getValueType(0);
|
|
|
|
SDOperand PermMask = N->getOperand(2);
|
|
|
|
unsigned NumElems = PermMask.getNumOperands();
|
|
|
|
SDOperand V = (i < NumElems) ? N->getOperand(0) : N->getOperand(1);
|
|
|
|
i %= NumElems;
|
|
|
|
if (V.getOpcode() == ISD::SCALAR_TO_VECTOR) {
|
|
|
|
return (i == 0)
|
|
|
|
? V.getOperand(0) : DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(VT));
|
|
|
|
} else if (V.getOpcode() == ISD::VECTOR_SHUFFLE) {
|
|
|
|
SDOperand Idx = PermMask.getOperand(i);
|
|
|
|
if (Idx.getOpcode() == ISD::UNDEF)
|
|
|
|
return DAG.getNode(ISD::UNDEF, MVT::getVectorBaseType(VT));
|
|
|
|
return getShuffleScalarElt(V.Val,cast<ConstantSDNode>(Idx)->getValue(),DAG);
|
|
|
|
}
|
|
|
|
return SDOperand();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isGAPlusOffset - Returns true (and the GlobalValue and the offset) if the
|
|
|
|
/// node is a GlobalAddress + an offset.
|
|
|
|
static bool isGAPlusOffset(SDNode *N, GlobalValue* &GA, int64_t &Offset) {
|
|
|
|
if (N->getOpcode() == X86ISD::Wrapper) {
|
|
|
|
if (dyn_cast<GlobalAddressSDNode>(N->getOperand(0))) {
|
|
|
|
GA = cast<GlobalAddressSDNode>(N->getOperand(0))->getGlobal();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (N->getOpcode() == ISD::ADD) {
|
|
|
|
SDOperand N1 = N->getOperand(0);
|
|
|
|
SDOperand N2 = N->getOperand(1);
|
|
|
|
if (isGAPlusOffset(N1.Val, GA, Offset)) {
|
|
|
|
ConstantSDNode *V = dyn_cast<ConstantSDNode>(N2);
|
|
|
|
if (V) {
|
|
|
|
Offset += V->getSignExtended();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (isGAPlusOffset(N2.Val, GA, Offset)) {
|
|
|
|
ConstantSDNode *V = dyn_cast<ConstantSDNode>(N1);
|
|
|
|
if (V) {
|
|
|
|
Offset += V->getSignExtended();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// isConsecutiveLoad - Returns true if N is loading from an address of Base
|
|
|
|
/// + Dist * Size.
|
|
|
|
static bool isConsecutiveLoad(SDNode *N, SDNode *Base, int Dist, int Size,
|
|
|
|
MachineFrameInfo *MFI) {
|
|
|
|
if (N->getOperand(0).Val != Base->getOperand(0).Val)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SDOperand Loc = N->getOperand(1);
|
|
|
|
SDOperand BaseLoc = Base->getOperand(1);
|
|
|
|
if (Loc.getOpcode() == ISD::FrameIndex) {
|
|
|
|
if (BaseLoc.getOpcode() != ISD::FrameIndex)
|
|
|
|
return false;
|
|
|
|
int FI = dyn_cast<FrameIndexSDNode>(Loc)->getIndex();
|
|
|
|
int BFI = dyn_cast<FrameIndexSDNode>(BaseLoc)->getIndex();
|
|
|
|
int FS = MFI->getObjectSize(FI);
|
|
|
|
int BFS = MFI->getObjectSize(BFI);
|
|
|
|
if (FS != BFS || FS != Size) return false;
|
|
|
|
return MFI->getObjectOffset(FI) == (MFI->getObjectOffset(BFI) + Dist*Size);
|
|
|
|
} else {
|
|
|
|
GlobalValue *GV1 = NULL;
|
|
|
|
GlobalValue *GV2 = NULL;
|
|
|
|
int64_t Offset1 = 0;
|
|
|
|
int64_t Offset2 = 0;
|
|
|
|
bool isGA1 = isGAPlusOffset(Loc.Val, GV1, Offset1);
|
|
|
|
bool isGA2 = isGAPlusOffset(BaseLoc.Val, GV2, Offset2);
|
|
|
|
if (isGA1 && isGA2 && GV1 == GV2)
|
|
|
|
return Offset1 == (Offset2 + Dist*Size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-07-11 05:37:44 +08:00
|
|
|
static bool isBaseAlignment16(SDNode *Base, MachineFrameInfo *MFI,
|
|
|
|
const X86Subtarget *Subtarget) {
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
GlobalValue *GV;
|
|
|
|
int64_t Offset;
|
|
|
|
if (isGAPlusOffset(Base, GV, Offset))
|
|
|
|
return (GV->getAlignment() >= 16 && (Offset % 16) == 0);
|
|
|
|
else {
|
|
|
|
assert(Base->getOpcode() == ISD::FrameIndex && "Unexpected base node!");
|
|
|
|
int BFI = dyn_cast<FrameIndexSDNode>(Base)->getIndex();
|
2006-07-11 05:37:44 +08:00
|
|
|
if (BFI < 0)
|
|
|
|
// Fixed objects do not specify alignment, however the offsets are known.
|
|
|
|
return ((Subtarget->getStackAlignment() % 16) == 0 &&
|
|
|
|
(MFI->getObjectOffset(BFI) % 16) == 0);
|
|
|
|
else
|
|
|
|
return MFI->getObjectAlignment(BFI) >= 16;
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// PerformShuffleCombine - Combine a vector_shuffle that is equal to
|
|
|
|
/// build_vector load1, load2, load3, load4, <0, 1, 2, 3> into a 128-bit load
|
|
|
|
/// if the load addresses are consecutive, non-overlapping, and in the right
|
|
|
|
/// order.
|
2006-07-11 05:37:44 +08:00
|
|
|
static SDOperand PerformShuffleCombine(SDNode *N, SelectionDAG &DAG,
|
|
|
|
const X86Subtarget *Subtarget) {
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo *MFI = MF.getFrameInfo();
|
|
|
|
MVT::ValueType VT = N->getValueType(0);
|
|
|
|
MVT::ValueType EVT = MVT::getVectorBaseType(VT);
|
|
|
|
SDOperand PermMask = N->getOperand(2);
|
|
|
|
int NumElems = (int)PermMask.getNumOperands();
|
|
|
|
SDNode *Base = NULL;
|
|
|
|
for (int i = 0; i < NumElems; ++i) {
|
|
|
|
SDOperand Idx = PermMask.getOperand(i);
|
|
|
|
if (Idx.getOpcode() == ISD::UNDEF) {
|
|
|
|
if (!Base) return SDOperand();
|
|
|
|
} else {
|
|
|
|
SDOperand Arg =
|
|
|
|
getShuffleScalarElt(N, cast<ConstantSDNode>(Idx)->getValue(), DAG);
|
|
|
|
if (!Arg.Val || Arg.getOpcode() != ISD::LOAD)
|
|
|
|
return SDOperand();
|
|
|
|
if (!Base)
|
|
|
|
Base = Arg.Val;
|
|
|
|
else if (!isConsecutiveLoad(Arg.Val, Base,
|
|
|
|
i, MVT::getSizeInBits(EVT)/8,MFI))
|
|
|
|
return SDOperand();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-11 05:37:44 +08:00
|
|
|
bool isAlign16 = isBaseAlignment16(Base->getOperand(1).Val, MFI, Subtarget);
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
if (isAlign16)
|
|
|
|
return DAG.getLoad(VT, Base->getOperand(0), Base->getOperand(1),
|
|
|
|
Base->getOperand(2));
|
2006-08-11 15:35:45 +08:00
|
|
|
else {
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
// Just use movups, it's shorter.
|
2006-08-11 17:08:15 +08:00
|
|
|
std::vector<MVT::ValueType> Tys;
|
|
|
|
Tys.push_back(MVT::v4f32);
|
|
|
|
Tys.push_back(MVT::Other);
|
|
|
|
SmallVector<SDOperand, 3> Ops;
|
|
|
|
Ops.push_back(Base->getOperand(0));
|
|
|
|
Ops.push_back(Base->getOperand(1));
|
|
|
|
Ops.push_back(Base->getOperand(2));
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
return DAG.getNode(ISD::BIT_CONVERT, VT,
|
2006-08-11 17:08:15 +08:00
|
|
|
DAG.getNode(X86ISD::LOAD_UA, Tys, &Ops[0], Ops.size()));
|
2006-08-11 15:35:45 +08:00
|
|
|
}
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand X86TargetLowering::PerformDAGCombine(SDNode *N,
|
|
|
|
DAGCombinerInfo &DCI) const {
|
|
|
|
TargetMachine &TM = getTargetMachine();
|
|
|
|
SelectionDAG &DAG = DCI.DAG;
|
|
|
|
switch (N->getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
case ISD::VECTOR_SHUFFLE:
|
2006-07-11 05:37:44 +08:00
|
|
|
return PerformShuffleCombine(N, DAG, Subtarget);
|
X86 target specific DAG combine: turn build_vector (load x), (load x+4),
(load x+8), (load x+12), <0, 1, 2, 3> to a single 128-bit load (aligned and
unaligned).
e.g.
__m128 test(float a, float b, float c, float d) {
return _mm_set_ps(d, c, b, a);
}
_test:
movups 4(%esp), %xmm0
ret
llvm-svn: 29042
2006-07-07 16:33:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SDOperand();
|
|
|
|
}
|
|
|
|
|
2006-07-06 06:17:51 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// X86 Inline Assembly Support
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2006-07-11 10:54:03 +08:00
|
|
|
/// getConstraintType - Given a constraint letter, return the type of
|
|
|
|
/// constraint it is for this target.
|
|
|
|
X86TargetLowering::ConstraintType
|
|
|
|
X86TargetLowering::getConstraintType(char ConstraintLetter) const {
|
|
|
|
switch (ConstraintLetter) {
|
2006-07-13 00:59:49 +08:00
|
|
|
case 'A':
|
|
|
|
case 'r':
|
|
|
|
case 'R':
|
|
|
|
case 'l':
|
|
|
|
case 'q':
|
|
|
|
case 'Q':
|
|
|
|
case 'x':
|
|
|
|
case 'Y':
|
|
|
|
return C_RegisterClass;
|
2006-07-11 10:54:03 +08:00
|
|
|
default: return TargetLowering::getConstraintType(ConstraintLetter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-01 03:43:35 +08:00
|
|
|
std::vector<unsigned> X86TargetLowering::
|
2006-02-22 08:56:39 +08:00
|
|
|
getRegClassForInlineAsmConstraint(const std::string &Constraint,
|
|
|
|
MVT::ValueType VT) const {
|
2006-02-01 03:43:35 +08:00
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
// FIXME: not handling fp-stack yet!
|
|
|
|
// FIXME: not handling MMX registers yet ('y' constraint).
|
|
|
|
switch (Constraint[0]) { // GCC X86 Constraint Letters
|
2006-07-11 10:54:03 +08:00
|
|
|
default: break; // Unknown constraint letter
|
|
|
|
case 'A': // EAX/EDX
|
|
|
|
if (VT == MVT::i32 || VT == MVT::i64)
|
|
|
|
return make_vector<unsigned>(X86::EAX, X86::EDX, 0);
|
|
|
|
break;
|
2006-02-01 03:43:35 +08:00
|
|
|
case 'r': // GENERAL_REGS
|
|
|
|
case 'R': // LEGACY_REGS
|
2006-05-06 08:29:37 +08:00
|
|
|
if (VT == MVT::i32)
|
|
|
|
return make_vector<unsigned>(X86::EAX, X86::EDX, X86::ECX, X86::EBX,
|
|
|
|
X86::ESI, X86::EDI, X86::EBP, X86::ESP, 0);
|
|
|
|
else if (VT == MVT::i16)
|
|
|
|
return make_vector<unsigned>(X86::AX, X86::DX, X86::CX, X86::BX,
|
|
|
|
X86::SI, X86::DI, X86::BP, X86::SP, 0);
|
|
|
|
else if (VT == MVT::i8)
|
|
|
|
return make_vector<unsigned>(X86::AL, X86::DL, X86::CL, X86::DL, 0);
|
|
|
|
break;
|
2006-02-01 03:43:35 +08:00
|
|
|
case 'l': // INDEX_REGS
|
2006-05-06 08:29:37 +08:00
|
|
|
if (VT == MVT::i32)
|
|
|
|
return make_vector<unsigned>(X86::EAX, X86::EDX, X86::ECX, X86::EBX,
|
|
|
|
X86::ESI, X86::EDI, X86::EBP, 0);
|
|
|
|
else if (VT == MVT::i16)
|
|
|
|
return make_vector<unsigned>(X86::AX, X86::DX, X86::CX, X86::BX,
|
|
|
|
X86::SI, X86::DI, X86::BP, 0);
|
|
|
|
else if (VT == MVT::i8)
|
|
|
|
return make_vector<unsigned>(X86::AL, X86::DL, X86::CL, X86::DL, 0);
|
|
|
|
break;
|
2006-02-01 03:43:35 +08:00
|
|
|
case 'q': // Q_REGS (GENERAL_REGS in 64-bit mode)
|
|
|
|
case 'Q': // Q_REGS
|
2006-05-06 08:29:37 +08:00
|
|
|
if (VT == MVT::i32)
|
|
|
|
return make_vector<unsigned>(X86::EAX, X86::EDX, X86::ECX, X86::EBX, 0);
|
|
|
|
else if (VT == MVT::i16)
|
|
|
|
return make_vector<unsigned>(X86::AX, X86::DX, X86::CX, X86::BX, 0);
|
|
|
|
else if (VT == MVT::i8)
|
|
|
|
return make_vector<unsigned>(X86::AL, X86::DL, X86::CL, X86::DL, 0);
|
|
|
|
break;
|
2006-02-01 03:43:35 +08:00
|
|
|
case 'x': // SSE_REGS if SSE1 allowed
|
|
|
|
if (Subtarget->hasSSE1())
|
|
|
|
return make_vector<unsigned>(X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
|
|
|
|
X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7,
|
|
|
|
0);
|
|
|
|
return std::vector<unsigned>();
|
|
|
|
case 'Y': // SSE_REGS if SSE2 allowed
|
|
|
|
if (Subtarget->hasSSE2())
|
|
|
|
return make_vector<unsigned>(X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3,
|
|
|
|
X86::XMM4, X86::XMM5, X86::XMM6, X86::XMM7,
|
|
|
|
0);
|
|
|
|
return std::vector<unsigned>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-22 08:56:39 +08:00
|
|
|
return std::vector<unsigned>();
|
2006-02-01 03:43:35 +08:00
|
|
|
}
|
2006-08-01 07:26:50 +08:00
|
|
|
|
|
|
|
std::pair<unsigned, const TargetRegisterClass*>
|
|
|
|
X86TargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
|
|
|
|
MVT::ValueType VT) const {
|
|
|
|
// Use the default implementation in TargetLowering to convert the register
|
|
|
|
// constraint into a member of a register class.
|
|
|
|
std::pair<unsigned, const TargetRegisterClass*> Res;
|
|
|
|
Res = TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
|
|
|
|
|
|
|
|
// Not found? Bail out.
|
|
|
|
if (Res.second == 0) return Res;
|
|
|
|
|
|
|
|
// Otherwise, check to see if this is a register class of the wrong value
|
|
|
|
// type. For example, we want to map "{ax},i32" -> {eax}, we don't want it to
|
|
|
|
// turn into {ax},{dx}.
|
|
|
|
if (Res.second->hasType(VT))
|
|
|
|
return Res; // Correct type already, nothing to do.
|
|
|
|
|
|
|
|
// All of the single-register GCC register classes map their values onto
|
|
|
|
// 16-bit register pieces "ax","dx","cx","bx","si","di","bp","sp". If we
|
|
|
|
// really want an 8-bit or 32-bit register, map to the appropriate register
|
|
|
|
// class and return the appropriate register.
|
|
|
|
if (Res.second != X86::GR16RegisterClass)
|
|
|
|
return Res;
|
|
|
|
|
|
|
|
if (VT == MVT::i8) {
|
|
|
|
unsigned DestReg = 0;
|
|
|
|
switch (Res.first) {
|
|
|
|
default: break;
|
|
|
|
case X86::AX: DestReg = X86::AL; break;
|
|
|
|
case X86::DX: DestReg = X86::DL; break;
|
|
|
|
case X86::CX: DestReg = X86::CL; break;
|
|
|
|
case X86::BX: DestReg = X86::BL; break;
|
|
|
|
}
|
|
|
|
if (DestReg) {
|
|
|
|
Res.first = DestReg;
|
|
|
|
Res.second = Res.second = X86::GR8RegisterClass;
|
|
|
|
}
|
|
|
|
} else if (VT == MVT::i32) {
|
|
|
|
unsigned DestReg = 0;
|
|
|
|
switch (Res.first) {
|
|
|
|
default: break;
|
|
|
|
case X86::AX: DestReg = X86::EAX; break;
|
|
|
|
case X86::DX: DestReg = X86::EDX; break;
|
|
|
|
case X86::CX: DestReg = X86::ECX; break;
|
|
|
|
case X86::BX: DestReg = X86::EBX; break;
|
|
|
|
case X86::SI: DestReg = X86::ESI; break;
|
|
|
|
case X86::DI: DestReg = X86::EDI; break;
|
|
|
|
case X86::BP: DestReg = X86::EBP; break;
|
|
|
|
case X86::SP: DestReg = X86::ESP; break;
|
|
|
|
}
|
|
|
|
if (DestReg) {
|
|
|
|
Res.first = DestReg;
|
|
|
|
Res.second = Res.second = X86::GR32RegisterClass;
|
|
|
|
}
|
2006-09-08 14:48:29 +08:00
|
|
|
} else if (VT == MVT::i64) {
|
|
|
|
unsigned DestReg = 0;
|
|
|
|
switch (Res.first) {
|
|
|
|
default: break;
|
|
|
|
case X86::AX: DestReg = X86::RAX; break;
|
|
|
|
case X86::DX: DestReg = X86::RDX; break;
|
|
|
|
case X86::CX: DestReg = X86::RCX; break;
|
|
|
|
case X86::BX: DestReg = X86::RBX; break;
|
|
|
|
case X86::SI: DestReg = X86::RSI; break;
|
|
|
|
case X86::DI: DestReg = X86::RDI; break;
|
|
|
|
case X86::BP: DestReg = X86::RBP; break;
|
|
|
|
case X86::SP: DestReg = X86::RSP; break;
|
|
|
|
}
|
|
|
|
if (DestReg) {
|
|
|
|
Res.first = DestReg;
|
|
|
|
Res.second = Res.second = X86::GR64RegisterClass;
|
|
|
|
}
|
2006-08-01 07:26:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|