2005-01-07 07:46:32 +00:00
|
|
|
//===-- SelectionDAG.cpp - Implement the SelectionDAG data structures -----===//
|
2005-04-21 22:36:52 +00:00
|
|
|
//
|
2003-10-20 19:43:21 +00:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by the LLVM research group and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
2005-04-21 22:36:52 +00:00
|
|
|
//
|
2003-10-20 19:43:21 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
2003-08-11 14:57:33 +00:00
|
|
|
//
|
2005-01-07 07:46:32 +00:00
|
|
|
// This implements the SelectionDAG class.
|
2003-08-11 14:57:33 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
2005-01-07 07:46:32 +00:00
|
|
|
#include "llvm/Constants.h"
|
|
|
|
#include "llvm/GlobalValue.h"
|
|
|
|
#include "llvm/Assembly/Writer.h"
|
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
2005-08-02 19:26:06 +00:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2005-08-19 21:34:13 +00:00
|
|
|
#include "llvm/Target/MRegisterInfo.h"
|
Remove the 3 HACK HACK HACKs I put in before, fixing them properly with
the new TLI that is available.
Implement support for handling out of range shifts. This allows us to
compile this code (a 64-bit rotate):
unsigned long long f3(unsigned long long x) {
return (x << 32) | (x >> (64-32));
}
into this:
f3:
mov %EDX, DWORD PTR [%ESP + 4]
mov %EAX, DWORD PTR [%ESP + 8]
ret
GCC produces this:
$ gcc t.c -masm=intel -O3 -S -o - -fomit-frame-pointer
..
f3:
push %ebx
mov %ebx, DWORD PTR [%esp+12]
mov %ecx, DWORD PTR [%esp+8]
mov %eax, %ebx
mov %edx, %ecx
pop %ebx
ret
The Simple ISEL produces (eww gross):
f3:
sub %ESP, 4
mov DWORD PTR [%ESP], %ESI
mov %EDX, DWORD PTR [%ESP + 8]
mov %ECX, DWORD PTR [%ESP + 12]
mov %EAX, 0
mov %ESI, 0
or %EAX, %ECX
or %EDX, %ESI
mov %ESI, DWORD PTR [%ESP]
add %ESP, 4
ret
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19780 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-23 04:39:44 +00:00
|
|
|
#include "llvm/Target/TargetLowering.h"
|
2005-08-16 18:33:07 +00:00
|
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
|
|
#include "llvm/Target/TargetMachine.h"
|
2005-12-19 23:11:49 +00:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2004-07-04 12:19:56 +00:00
|
|
|
#include <iostream>
|
2005-01-07 21:09:16 +00:00
|
|
|
#include <set>
|
2005-01-07 07:46:32 +00:00
|
|
|
#include <cmath>
|
2005-01-09 20:41:56 +00:00
|
|
|
#include <algorithm>
|
2004-06-02 04:28:06 +00:00
|
|
|
using namespace llvm;
|
2003-11-11 22:41:34 +00:00
|
|
|
|
Add some folds for == and != comparisons. This allows us to
codegen this loop in stepanov:
no_exit.i: ; preds = %entry, %no_exit.i, %then.i, %_Z5checkd.exit
%i.0.0 = phi int [ 0, %entry ], [ %i.0.0, %no_exit.i ], [ %inc.0, %_Z5checkd.exit ], [ %inc.012, %then.i ] ; <int> [#uses=3]
%indvar = phi uint [ %indvar.next, %no_exit.i ], [ 0, %entry ], [ 0, %then.i ], [ 0, %_Z5checkd.exit ] ; <uint> [#uses=3]
%result_addr.i.0 = phi double [ %tmp.4.i.i, %no_exit.i ], [ 0.000000e+00, %entry ], [ 0.000000e+00, %then.i ], [ 0.000000e+00, %_Z5checkd.exit ] ; <double> [#uses=1]
%first_addr.0.i.2.rec = cast uint %indvar to int ; <int> [#uses=1]
%first_addr.0.i.2 = getelementptr [2000 x double]* %data, int 0, uint %indvar ; <double*> [#uses=1]
%inc.i.rec = add int %first_addr.0.i.2.rec, 1 ; <int> [#uses=1]
%inc.i = getelementptr [2000 x double]* %data, int 0, int %inc.i.rec ; <double*> [#uses=1]
%tmp.3.i.i = load double* %first_addr.0.i.2 ; <double> [#uses=1]
%tmp.4.i.i = add double %result_addr.i.0, %tmp.3.i.i ; <double> [#uses=2]
%tmp.2.i = seteq double* %inc.i, getelementptr ([2000 x double]* %data, int 0, int 2000) ; <bool> [#uses=1]
%indvar.next = add uint %indvar, 1 ; <uint> [#uses=1]
br bool %tmp.2.i, label %_Z10accumulateIPddET0_T_S2_S1_.exit, label %no_exit.i
To this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
movl %eax, %ecx
shll $3, %ecx
cmpl $16000, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
instead of this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
leal data(,%eax,8), %ecx
leal data+16000, %edx
cmpl %edx, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19425 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-09 20:52:51 +00:00
|
|
|
static bool isCommutativeBinOp(unsigned Opcode) {
|
|
|
|
switch (Opcode) {
|
|
|
|
case ISD::ADD:
|
|
|
|
case ISD::MUL:
|
2006-01-16 08:07:10 +00:00
|
|
|
case ISD::MULHU:
|
|
|
|
case ISD::MULHS:
|
2005-09-28 22:28:18 +00:00
|
|
|
case ISD::FADD:
|
|
|
|
case ISD::FMUL:
|
Add some folds for == and != comparisons. This allows us to
codegen this loop in stepanov:
no_exit.i: ; preds = %entry, %no_exit.i, %then.i, %_Z5checkd.exit
%i.0.0 = phi int [ 0, %entry ], [ %i.0.0, %no_exit.i ], [ %inc.0, %_Z5checkd.exit ], [ %inc.012, %then.i ] ; <int> [#uses=3]
%indvar = phi uint [ %indvar.next, %no_exit.i ], [ 0, %entry ], [ 0, %then.i ], [ 0, %_Z5checkd.exit ] ; <uint> [#uses=3]
%result_addr.i.0 = phi double [ %tmp.4.i.i, %no_exit.i ], [ 0.000000e+00, %entry ], [ 0.000000e+00, %then.i ], [ 0.000000e+00, %_Z5checkd.exit ] ; <double> [#uses=1]
%first_addr.0.i.2.rec = cast uint %indvar to int ; <int> [#uses=1]
%first_addr.0.i.2 = getelementptr [2000 x double]* %data, int 0, uint %indvar ; <double*> [#uses=1]
%inc.i.rec = add int %first_addr.0.i.2.rec, 1 ; <int> [#uses=1]
%inc.i = getelementptr [2000 x double]* %data, int 0, int %inc.i.rec ; <double*> [#uses=1]
%tmp.3.i.i = load double* %first_addr.0.i.2 ; <double> [#uses=1]
%tmp.4.i.i = add double %result_addr.i.0, %tmp.3.i.i ; <double> [#uses=2]
%tmp.2.i = seteq double* %inc.i, getelementptr ([2000 x double]* %data, int 0, int 2000) ; <bool> [#uses=1]
%indvar.next = add uint %indvar, 1 ; <uint> [#uses=1]
br bool %tmp.2.i, label %_Z10accumulateIPddET0_T_S2_S1_.exit, label %no_exit.i
To this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
movl %eax, %ecx
shll $3, %ecx
cmpl $16000, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
instead of this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
leal data(,%eax,8), %ecx
leal data+16000, %edx
cmpl %edx, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19425 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-09 20:52:51 +00:00
|
|
|
case ISD::AND:
|
|
|
|
case ISD::OR:
|
|
|
|
case ISD::XOR: return true;
|
|
|
|
default: return false; // FIXME: Need commutative info for user ops!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isAssociativeBinOp(unsigned Opcode) {
|
|
|
|
switch (Opcode) {
|
|
|
|
case ISD::ADD:
|
|
|
|
case ISD::MUL:
|
|
|
|
case ISD::AND:
|
|
|
|
case ISD::OR:
|
|
|
|
case ISD::XOR: return true;
|
|
|
|
default: return false; // FIXME: Need associative info for user ops!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// isInvertibleForFree - Return true if there is no cost to emitting the logical
|
|
|
|
// inverse of this node.
|
|
|
|
static bool isInvertibleForFree(SDOperand N) {
|
|
|
|
if (isa<ConstantSDNode>(N.Val)) return true;
|
2005-08-09 20:20:18 +00:00
|
|
|
if (N.Val->getOpcode() == ISD::SETCC && N.Val->hasOneUse())
|
Add some folds for == and != comparisons. This allows us to
codegen this loop in stepanov:
no_exit.i: ; preds = %entry, %no_exit.i, %then.i, %_Z5checkd.exit
%i.0.0 = phi int [ 0, %entry ], [ %i.0.0, %no_exit.i ], [ %inc.0, %_Z5checkd.exit ], [ %inc.012, %then.i ] ; <int> [#uses=3]
%indvar = phi uint [ %indvar.next, %no_exit.i ], [ 0, %entry ], [ 0, %then.i ], [ 0, %_Z5checkd.exit ] ; <uint> [#uses=3]
%result_addr.i.0 = phi double [ %tmp.4.i.i, %no_exit.i ], [ 0.000000e+00, %entry ], [ 0.000000e+00, %then.i ], [ 0.000000e+00, %_Z5checkd.exit ] ; <double> [#uses=1]
%first_addr.0.i.2.rec = cast uint %indvar to int ; <int> [#uses=1]
%first_addr.0.i.2 = getelementptr [2000 x double]* %data, int 0, uint %indvar ; <double*> [#uses=1]
%inc.i.rec = add int %first_addr.0.i.2.rec, 1 ; <int> [#uses=1]
%inc.i = getelementptr [2000 x double]* %data, int 0, int %inc.i.rec ; <double*> [#uses=1]
%tmp.3.i.i = load double* %first_addr.0.i.2 ; <double> [#uses=1]
%tmp.4.i.i = add double %result_addr.i.0, %tmp.3.i.i ; <double> [#uses=2]
%tmp.2.i = seteq double* %inc.i, getelementptr ([2000 x double]* %data, int 0, int 2000) ; <bool> [#uses=1]
%indvar.next = add uint %indvar, 1 ; <uint> [#uses=1]
br bool %tmp.2.i, label %_Z10accumulateIPddET0_T_S2_S1_.exit, label %no_exit.i
To this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
movl %eax, %ecx
shll $3, %ecx
cmpl $16000, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
instead of this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
leal data(,%eax,8), %ecx
leal data+16000, %edx
cmpl %edx, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19425 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-09 20:52:51 +00:00
|
|
|
return true;
|
2005-04-21 22:36:52 +00:00
|
|
|
return false;
|
Add some folds for == and != comparisons. This allows us to
codegen this loop in stepanov:
no_exit.i: ; preds = %entry, %no_exit.i, %then.i, %_Z5checkd.exit
%i.0.0 = phi int [ 0, %entry ], [ %i.0.0, %no_exit.i ], [ %inc.0, %_Z5checkd.exit ], [ %inc.012, %then.i ] ; <int> [#uses=3]
%indvar = phi uint [ %indvar.next, %no_exit.i ], [ 0, %entry ], [ 0, %then.i ], [ 0, %_Z5checkd.exit ] ; <uint> [#uses=3]
%result_addr.i.0 = phi double [ %tmp.4.i.i, %no_exit.i ], [ 0.000000e+00, %entry ], [ 0.000000e+00, %then.i ], [ 0.000000e+00, %_Z5checkd.exit ] ; <double> [#uses=1]
%first_addr.0.i.2.rec = cast uint %indvar to int ; <int> [#uses=1]
%first_addr.0.i.2 = getelementptr [2000 x double]* %data, int 0, uint %indvar ; <double*> [#uses=1]
%inc.i.rec = add int %first_addr.0.i.2.rec, 1 ; <int> [#uses=1]
%inc.i = getelementptr [2000 x double]* %data, int 0, int %inc.i.rec ; <double*> [#uses=1]
%tmp.3.i.i = load double* %first_addr.0.i.2 ; <double> [#uses=1]
%tmp.4.i.i = add double %result_addr.i.0, %tmp.3.i.i ; <double> [#uses=2]
%tmp.2.i = seteq double* %inc.i, getelementptr ([2000 x double]* %data, int 0, int 2000) ; <bool> [#uses=1]
%indvar.next = add uint %indvar, 1 ; <uint> [#uses=1]
br bool %tmp.2.i, label %_Z10accumulateIPddET0_T_S2_S1_.exit, label %no_exit.i
To this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
movl %eax, %ecx
shll $3, %ecx
cmpl $16000, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
instead of this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
leal data(,%eax,8), %ecx
leal data+16000, %edx
cmpl %edx, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19425 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-09 20:52:51 +00:00
|
|
|
}
|
|
|
|
|
2005-08-17 20:08:02 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ConstantFPSDNode Class
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// isExactlyValue - We don't rely on operator== working on double values, as
|
|
|
|
/// it returns true for things that are clearly not equal, like -0.0 and 0.0.
|
|
|
|
/// As such, this method can be used to do an exact bit-for-bit comparison of
|
|
|
|
/// two floating point values.
|
|
|
|
bool ConstantFPSDNode::isExactlyValue(double V) const {
|
|
|
|
return DoubleToBits(V) == DoubleToBits(Value);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ISD Class
|
|
|
|
//===----------------------------------------------------------------------===//
|
Add some folds for == and != comparisons. This allows us to
codegen this loop in stepanov:
no_exit.i: ; preds = %entry, %no_exit.i, %then.i, %_Z5checkd.exit
%i.0.0 = phi int [ 0, %entry ], [ %i.0.0, %no_exit.i ], [ %inc.0, %_Z5checkd.exit ], [ %inc.012, %then.i ] ; <int> [#uses=3]
%indvar = phi uint [ %indvar.next, %no_exit.i ], [ 0, %entry ], [ 0, %then.i ], [ 0, %_Z5checkd.exit ] ; <uint> [#uses=3]
%result_addr.i.0 = phi double [ %tmp.4.i.i, %no_exit.i ], [ 0.000000e+00, %entry ], [ 0.000000e+00, %then.i ], [ 0.000000e+00, %_Z5checkd.exit ] ; <double> [#uses=1]
%first_addr.0.i.2.rec = cast uint %indvar to int ; <int> [#uses=1]
%first_addr.0.i.2 = getelementptr [2000 x double]* %data, int 0, uint %indvar ; <double*> [#uses=1]
%inc.i.rec = add int %first_addr.0.i.2.rec, 1 ; <int> [#uses=1]
%inc.i = getelementptr [2000 x double]* %data, int 0, int %inc.i.rec ; <double*> [#uses=1]
%tmp.3.i.i = load double* %first_addr.0.i.2 ; <double> [#uses=1]
%tmp.4.i.i = add double %result_addr.i.0, %tmp.3.i.i ; <double> [#uses=2]
%tmp.2.i = seteq double* %inc.i, getelementptr ([2000 x double]* %data, int 0, int 2000) ; <bool> [#uses=1]
%indvar.next = add uint %indvar, 1 ; <uint> [#uses=1]
br bool %tmp.2.i, label %_Z10accumulateIPddET0_T_S2_S1_.exit, label %no_exit.i
To this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
movl %eax, %ecx
shll $3, %ecx
cmpl $16000, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
instead of this:
.LBB_Z4testIPddEvT_S1_T0__1: # no_exit.i
fldl data(,%eax,8)
fldl 16(%esp)
faddp %st(1)
fstpl 16(%esp)
incl %eax
leal data(,%eax,8), %ecx
leal data+16000, %edx
cmpl %edx, %ecx
#FP_REG_KILL
jne .LBB_Z4testIPddEvT_S1_T0__1 # no_exit.i
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19425 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-09 20:52:51 +00:00
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
/// getSetCCSwappedOperands - Return the operation corresponding to (Y op X)
|
|
|
|
/// when given the operation for (X op Y).
|
|
|
|
ISD::CondCode ISD::getSetCCSwappedOperands(ISD::CondCode Operation) {
|
|
|
|
// To perform this operation, we just need to swap the L and G bits of the
|
|
|
|
// operation.
|
|
|
|
unsigned OldL = (Operation >> 2) & 1;
|
|
|
|
unsigned OldG = (Operation >> 1) & 1;
|
|
|
|
return ISD::CondCode((Operation & ~6) | // Keep the N, U, E bits
|
|
|
|
(OldL << 1) | // New G bit
|
|
|
|
(OldG << 2)); // New L bit.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getSetCCInverse - Return the operation corresponding to !(X op Y), where
|
|
|
|
/// 'op' is a valid SetCC operation.
|
|
|
|
ISD::CondCode ISD::getSetCCInverse(ISD::CondCode Op, bool isInteger) {
|
|
|
|
unsigned Operation = Op;
|
|
|
|
if (isInteger)
|
|
|
|
Operation ^= 7; // Flip L, G, E bits, but not U.
|
|
|
|
else
|
|
|
|
Operation ^= 15; // Flip all of the condition bits.
|
|
|
|
if (Operation > ISD::SETTRUE2)
|
|
|
|
Operation &= ~8; // Don't let N and U bits get set.
|
|
|
|
return ISD::CondCode(Operation);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// isSignedOp - For an integer comparison, return 1 if the comparison is a
|
|
|
|
/// signed operation and 2 if the result is an unsigned comparison. Return zero
|
|
|
|
/// if the operation does not depend on the sign of the input (setne and seteq).
|
|
|
|
static int isSignedOp(ISD::CondCode Opcode) {
|
|
|
|
switch (Opcode) {
|
|
|
|
default: assert(0 && "Illegal integer setcc operation!");
|
|
|
|
case ISD::SETEQ:
|
|
|
|
case ISD::SETNE: return 0;
|
|
|
|
case ISD::SETLT:
|
|
|
|
case ISD::SETLE:
|
|
|
|
case ISD::SETGT:
|
|
|
|
case ISD::SETGE: return 1;
|
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETUGE: return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getSetCCOrOperation - Return the result of a logical OR between different
|
|
|
|
/// comparisons of identical values: ((X op1 Y) | (X op2 Y)). This function
|
|
|
|
/// returns SETCC_INVALID if it is not possible to represent the resultant
|
|
|
|
/// comparison.
|
|
|
|
ISD::CondCode ISD::getSetCCOrOperation(ISD::CondCode Op1, ISD::CondCode Op2,
|
|
|
|
bool isInteger) {
|
|
|
|
if (isInteger && (isSignedOp(Op1) | isSignedOp(Op2)) == 3)
|
|
|
|
// Cannot fold a signed integer setcc with an unsigned integer setcc.
|
|
|
|
return ISD::SETCC_INVALID;
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
unsigned Op = Op1 | Op2; // Combine all of the condition bits.
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
// If the N and U bits get set then the resultant comparison DOES suddenly
|
|
|
|
// care about orderedness, and is true when ordered.
|
|
|
|
if (Op > ISD::SETTRUE2)
|
|
|
|
Op &= ~16; // Clear the N bit.
|
|
|
|
return ISD::CondCode(Op);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getSetCCAndOperation - Return the result of a logical AND between different
|
|
|
|
/// comparisons of identical values: ((X op1 Y) & (X op2 Y)). This
|
|
|
|
/// function returns zero if it is not possible to represent the resultant
|
|
|
|
/// comparison.
|
|
|
|
ISD::CondCode ISD::getSetCCAndOperation(ISD::CondCode Op1, ISD::CondCode Op2,
|
|
|
|
bool isInteger) {
|
|
|
|
if (isInteger && (isSignedOp(Op1) | isSignedOp(Op2)) == 3)
|
|
|
|
// Cannot fold a signed setcc with an unsigned setcc.
|
2005-04-21 22:36:52 +00:00
|
|
|
return ISD::SETCC_INVALID;
|
2005-01-07 07:46:32 +00:00
|
|
|
|
|
|
|
// Combine all of the condition bits.
|
|
|
|
return ISD::CondCode(Op1 & Op2);
|
|
|
|
}
|
|
|
|
|
Remove the 3 HACK HACK HACKs I put in before, fixing them properly with
the new TLI that is available.
Implement support for handling out of range shifts. This allows us to
compile this code (a 64-bit rotate):
unsigned long long f3(unsigned long long x) {
return (x << 32) | (x >> (64-32));
}
into this:
f3:
mov %EDX, DWORD PTR [%ESP + 4]
mov %EAX, DWORD PTR [%ESP + 8]
ret
GCC produces this:
$ gcc t.c -masm=intel -O3 -S -o - -fomit-frame-pointer
..
f3:
push %ebx
mov %ebx, DWORD PTR [%esp+12]
mov %ecx, DWORD PTR [%esp+8]
mov %eax, %ebx
mov %edx, %ecx
pop %ebx
ret
The Simple ISEL produces (eww gross):
f3:
sub %ESP, 4
mov DWORD PTR [%ESP], %ESI
mov %EDX, DWORD PTR [%ESP + 8]
mov %ECX, DWORD PTR [%ESP + 12]
mov %EAX, 0
mov %ESI, 0
or %EAX, %ECX
or %EDX, %ESI
mov %ESI, DWORD PTR [%ESP]
add %ESP, 4
ret
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19780 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-23 04:39:44 +00:00
|
|
|
const TargetMachine &SelectionDAG::getTarget() const {
|
|
|
|
return TLI.getTargetMachine();
|
|
|
|
}
|
|
|
|
|
2005-08-17 20:08:02 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// SelectionDAG Class
|
|
|
|
//===----------------------------------------------------------------------===//
|
Remove the 3 HACK HACK HACKs I put in before, fixing them properly with
the new TLI that is available.
Implement support for handling out of range shifts. This allows us to
compile this code (a 64-bit rotate):
unsigned long long f3(unsigned long long x) {
return (x << 32) | (x >> (64-32));
}
into this:
f3:
mov %EDX, DWORD PTR [%ESP + 4]
mov %EAX, DWORD PTR [%ESP + 8]
ret
GCC produces this:
$ gcc t.c -masm=intel -O3 -S -o - -fomit-frame-pointer
..
f3:
push %ebx
mov %ebx, DWORD PTR [%esp+12]
mov %ecx, DWORD PTR [%esp+8]
mov %eax, %ebx
mov %edx, %ecx
pop %ebx
ret
The Simple ISEL produces (eww gross):
f3:
sub %ESP, 4
mov DWORD PTR [%ESP], %ESI
mov %EDX, DWORD PTR [%ESP + 8]
mov %ECX, DWORD PTR [%ESP + 12]
mov %EAX, 0
mov %ESI, 0
or %EAX, %ECX
or %EDX, %ESI
mov %ESI, DWORD PTR [%ESP]
add %ESP, 4
ret
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@19780 91177308-0d34-0410-b5e6-96231b3b80d8
2005-01-23 04:39:44 +00:00
|
|
|
|
2005-01-07 21:09:16 +00:00
|
|
|
/// RemoveDeadNodes - This method deletes all unreachable nodes in the
|
|
|
|
/// SelectionDAG, including nodes (like loads) that have uses of their token
|
|
|
|
/// chain but no other uses and no side effect. If a node is passed in as an
|
|
|
|
/// argument, it is used as the seed for node deletion.
|
|
|
|
void SelectionDAG::RemoveDeadNodes(SDNode *N) {
|
|
|
|
// Create a dummy node (which is not added to allnodes), that adds a reference
|
|
|
|
// to the root node, preventing it from being deleted.
|
2005-10-05 06:35:28 +00:00
|
|
|
HandleSDNode Dummy(getRoot());
|
2005-01-07 21:09:16 +00:00
|
|
|
|
2005-11-08 18:52:27 +00:00
|
|
|
bool MadeChange = false;
|
|
|
|
|
2005-08-17 19:00:20 +00:00
|
|
|
// If we have a hint to start from, use it.
|
2005-11-08 18:52:27 +00:00
|
|
|
if (N && N->use_empty()) {
|
|
|
|
DestroyDeadNode(N);
|
|
|
|
MadeChange = true;
|
|
|
|
}
|
2005-01-07 21:09:16 +00:00
|
|
|
|
2005-11-09 23:47:37 +00:00
|
|
|
for (allnodes_iterator I = allnodes_begin(), E = allnodes_end(); I != E; ++I)
|
|
|
|
if (I->use_empty() && I->getOpcode() != 65535) {
|
|
|
|
// Node is dead, recursively delete newly dead uses.
|
|
|
|
DestroyDeadNode(I);
|
2005-11-08 18:52:27 +00:00
|
|
|
MadeChange = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Walk the nodes list, removing the nodes we've marked as dead.
|
|
|
|
if (MadeChange) {
|
2005-11-09 23:47:37 +00:00
|
|
|
for (allnodes_iterator I = allnodes_begin(), E = allnodes_end(); I != E; ) {
|
|
|
|
SDNode *N = I++;
|
|
|
|
if (N->use_empty())
|
|
|
|
AllNodes.erase(N);
|
|
|
|
}
|
2005-11-08 18:52:27 +00:00
|
|
|
}
|
|
|
|
|
2005-01-07 21:09:16 +00:00
|
|
|
// If the root changed (e.g. it was a dead load, update the root).
|
2005-10-05 06:35:28 +00:00
|
|
|
setRoot(Dummy.getValue());
|
2005-01-07 21:09:16 +00:00
|
|
|
}
|
|
|
|
|
2005-11-08 18:52:27 +00:00
|
|
|
/// DestroyDeadNode - We know that N is dead. Nuke it from the CSE maps for the
|
|
|
|
/// graph. If it is the last user of any of its operands, recursively process
|
|
|
|
/// them the same way.
|
|
|
|
///
|
|
|
|
void SelectionDAG::DestroyDeadNode(SDNode *N) {
|
2005-01-07 21:09:16 +00:00
|
|
|
// Okay, we really are going to delete this node. First take this out of the
|
|
|
|
// appropriate CSE map.
|
2005-08-16 18:17:10 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
|
|
|
|
// Next, brutally remove the operand list. This is safe to do, as there are
|
|
|
|
// no cycles in the graph.
|
2005-11-08 22:07:03 +00:00
|
|
|
for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I) {
|
|
|
|
SDNode *O = I->Val;
|
2005-08-16 18:17:10 +00:00
|
|
|
O->removeUser(N);
|
|
|
|
|
|
|
|
// Now that we removed this operand, see if there are no uses of it left.
|
2005-11-08 18:52:27 +00:00
|
|
|
if (O->use_empty())
|
|
|
|
DestroyDeadNode(O);
|
2005-08-16 18:17:10 +00:00
|
|
|
}
|
2005-11-08 22:07:03 +00:00
|
|
|
delete[] N->OperandList;
|
|
|
|
N->OperandList = 0;
|
|
|
|
N->NumOperands = 0;
|
2005-11-08 18:52:27 +00:00
|
|
|
|
|
|
|
// Mark the node as dead.
|
|
|
|
N->MorphNodeTo(65535);
|
2005-08-16 18:17:10 +00:00
|
|
|
}
|
|
|
|
|
2005-08-29 21:59:31 +00:00
|
|
|
void SelectionDAG::DeleteNode(SDNode *N) {
|
|
|
|
assert(N->use_empty() && "Cannot delete a node that is not dead!");
|
|
|
|
|
|
|
|
// First take this out of the appropriate CSE map.
|
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
|
2005-09-07 05:37:01 +00:00
|
|
|
// Finally, remove uses due to operands of this node, remove from the
|
|
|
|
// AllNodes list, and delete the node.
|
|
|
|
DeleteNodeNotInCSEMaps(N);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SelectionDAG::DeleteNodeNotInCSEMaps(SDNode *N) {
|
|
|
|
|
2005-08-29 21:59:31 +00:00
|
|
|
// Remove it from the AllNodes list.
|
2005-11-09 23:47:37 +00:00
|
|
|
AllNodes.remove(N);
|
2005-08-29 21:59:31 +00:00
|
|
|
|
|
|
|
// Drop all of the operands and decrement used nodes use counts.
|
2005-11-08 22:07:03 +00:00
|
|
|
for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I)
|
|
|
|
I->Val->removeUser(N);
|
|
|
|
delete[] N->OperandList;
|
|
|
|
N->OperandList = 0;
|
|
|
|
N->NumOperands = 0;
|
2005-08-29 21:59:31 +00:00
|
|
|
|
|
|
|
delete N;
|
|
|
|
}
|
|
|
|
|
2005-08-16 18:17:10 +00:00
|
|
|
/// RemoveNodeFromCSEMaps - Take the specified node out of the CSE map that
|
|
|
|
/// correspond to it. This is useful when we're about to delete or repurpose
|
|
|
|
/// the node. We don't want future request for structurally identical nodes
|
|
|
|
/// to return N anymore.
|
|
|
|
void SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) {
|
2005-09-02 19:15:44 +00:00
|
|
|
bool Erased = false;
|
2005-01-07 21:09:16 +00:00
|
|
|
switch (N->getOpcode()) {
|
2005-10-05 06:35:28 +00:00
|
|
|
case ISD::HANDLENODE: return; // noop.
|
2005-01-07 21:09:16 +00:00
|
|
|
case ISD::Constant:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = Constants.erase(std::make_pair(cast<ConstantSDNode>(N)->getValue(),
|
|
|
|
N->getValueType(0)));
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
2005-08-17 00:34:06 +00:00
|
|
|
case ISD::TargetConstant:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = TargetConstants.erase(std::make_pair(
|
|
|
|
cast<ConstantSDNode>(N)->getValue(),
|
|
|
|
N->getValueType(0)));
|
2005-08-17 00:34:06 +00:00
|
|
|
break;
|
2005-02-17 20:17:32 +00:00
|
|
|
case ISD::ConstantFP: {
|
2005-08-17 19:34:49 +00:00
|
|
|
uint64_t V = DoubleToBits(cast<ConstantFPSDNode>(N)->getValue());
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = ConstantFPs.erase(std::make_pair(V, N->getValueType(0)));
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
2005-02-17 20:17:32 +00:00
|
|
|
}
|
2006-01-29 06:26:56 +00:00
|
|
|
case ISD::TargetConstantFP: {
|
|
|
|
uint64_t V = DoubleToBits(cast<ConstantFPSDNode>(N)->getValue());
|
|
|
|
Erased = TargetConstantFPs.erase(std::make_pair(V, N->getValueType(0)));
|
|
|
|
break;
|
|
|
|
}
|
2005-11-29 06:21:05 +00:00
|
|
|
case ISD::STRING:
|
|
|
|
Erased = StringNodes.erase(cast<StringSDNode>(N)->getValue());
|
|
|
|
break;
|
2005-08-09 20:20:18 +00:00
|
|
|
case ISD::CONDCODE:
|
|
|
|
assert(CondCodeNodes[cast<CondCodeSDNode>(N)->get()] &&
|
|
|
|
"Cond code doesn't exist!");
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = CondCodeNodes[cast<CondCodeSDNode>(N)->get()] != 0;
|
2005-08-09 20:20:18 +00:00
|
|
|
CondCodeNodes[cast<CondCodeSDNode>(N)->get()] = 0;
|
|
|
|
break;
|
2005-11-30 02:49:21 +00:00
|
|
|
case ISD::GlobalAddress: {
|
|
|
|
GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(N);
|
|
|
|
Erased = GlobalValues.erase(std::make_pair(GN->getGlobal(),
|
|
|
|
GN->getOffset()));
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
2005-11-30 02:49:21 +00:00
|
|
|
}
|
|
|
|
case ISD::TargetGlobalAddress: {
|
|
|
|
GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(N);
|
|
|
|
Erased =TargetGlobalValues.erase(std::make_pair(GN->getGlobal(),
|
|
|
|
GN->getOffset()));
|
2005-08-19 22:31:04 +00:00
|
|
|
break;
|
2005-11-30 02:49:21 +00:00
|
|
|
}
|
2005-01-07 21:09:16 +00:00
|
|
|
case ISD::FrameIndex:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = FrameIndices.erase(cast<FrameIndexSDNode>(N)->getIndex());
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
2005-08-25 00:43:01 +00:00
|
|
|
case ISD::TargetFrameIndex:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = TargetFrameIndices.erase(cast<FrameIndexSDNode>(N)->getIndex());
|
2005-08-25 00:43:01 +00:00
|
|
|
break;
|
2005-01-07 21:09:16 +00:00
|
|
|
case ISD::ConstantPool:
|
2006-01-31 22:23:14 +00:00
|
|
|
Erased = ConstantPoolIndices.
|
|
|
|
erase(std::make_pair(cast<ConstantPoolSDNode>(N)->get(),
|
|
|
|
cast<ConstantPoolSDNode>(N)->getAlignment()));
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
2005-08-25 05:03:06 +00:00
|
|
|
case ISD::TargetConstantPool:
|
2006-01-31 22:23:14 +00:00
|
|
|
Erased = TargetConstantPoolIndices.
|
|
|
|
erase(std::make_pair(cast<ConstantPoolSDNode>(N)->get(),
|
|
|
|
cast<ConstantPoolSDNode>(N)->getAlignment()));
|
2005-08-25 05:03:06 +00:00
|
|
|
break;
|
2005-01-07 21:09:16 +00:00
|
|
|
case ISD::BasicBlock:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = BBNodes.erase(cast<BasicBlockSDNode>(N)->getBasicBlock());
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
|
|
|
case ISD::ExternalSymbol:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = ExternalSymbols.erase(cast<ExternalSymbolSDNode>(N)->getSymbol());
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
2005-10-23 03:40:17 +00:00
|
|
|
case ISD::TargetExternalSymbol:
|
2006-01-28 10:09:25 +00:00
|
|
|
Erased =
|
|
|
|
TargetExternalSymbols.erase(cast<ExternalSymbolSDNode>(N)->getSymbol());
|
2005-10-23 03:40:17 +00:00
|
|
|
break;
|
2005-07-10 00:07:11 +00:00
|
|
|
case ISD::VALUETYPE:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = ValueTypeNodes[cast<VTSDNode>(N)->getVT()] != 0;
|
2005-07-10 00:07:11 +00:00
|
|
|
ValueTypeNodes[cast<VTSDNode>(N)->getVT()] = 0;
|
|
|
|
break;
|
2005-08-16 21:55:35 +00:00
|
|
|
case ISD::Register:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = RegNodes.erase(std::make_pair(cast<RegisterSDNode>(N)->getReg(),
|
|
|
|
N->getValueType(0)));
|
2005-08-16 21:55:35 +00:00
|
|
|
break;
|
2005-08-05 16:55:31 +00:00
|
|
|
case ISD::SRCVALUE: {
|
|
|
|
SrcValueSDNode *SVN = cast<SrcValueSDNode>(N);
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased =ValueNodes.erase(std::make_pair(SVN->getValue(), SVN->getOffset()));
|
2005-08-05 16:55:31 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-01-07 21:09:16 +00:00
|
|
|
case ISD::LOAD:
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased = Loads.erase(std::make_pair(N->getOperand(1),
|
|
|
|
std::make_pair(N->getOperand(0),
|
|
|
|
N->getValueType(0))));
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
|
|
|
default:
|
2005-09-02 19:15:44 +00:00
|
|
|
if (N->getNumValues() == 1) {
|
2005-09-02 19:36:17 +00:00
|
|
|
if (N->getNumOperands() == 0) {
|
|
|
|
Erased = NullaryOps.erase(std::make_pair(N->getOpcode(),
|
|
|
|
N->getValueType(0)));
|
|
|
|
} else if (N->getNumOperands() == 1) {
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased =
|
|
|
|
UnaryOps.erase(std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(N->getOperand(0),
|
|
|
|
N->getValueType(0))));
|
|
|
|
} else if (N->getNumOperands() == 2) {
|
|
|
|
Erased =
|
|
|
|
BinaryOps.erase(std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(N->getOperand(0),
|
|
|
|
N->getOperand(1))));
|
|
|
|
} else {
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
|
|
|
Erased =
|
|
|
|
OneResultNodes.erase(std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(N->getValueType(0),
|
|
|
|
Ops)));
|
|
|
|
}
|
2005-05-14 07:42:29 +00:00
|
|
|
} else {
|
2005-05-14 06:20:26 +00:00
|
|
|
// Remove the node from the ArbitraryNodes map.
|
|
|
|
std::vector<MVT::ValueType> RV(N->value_begin(), N->value_end());
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
2005-09-02 19:15:44 +00:00
|
|
|
Erased =
|
|
|
|
ArbitraryNodes.erase(std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(RV, Ops)));
|
2005-05-14 06:20:26 +00:00
|
|
|
}
|
2005-01-07 21:09:16 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-09-02 19:15:44 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
// Verify that the node was actually in one of the CSE maps, unless it has a
|
|
|
|
// flag result (which cannot be CSE'd) or is one of the special cases that are
|
|
|
|
// not subject to CSE.
|
|
|
|
if (!Erased && N->getValueType(N->getNumValues()-1) != MVT::Flag &&
|
2006-01-29 07:58:15 +00:00
|
|
|
!N->isTargetOpcode()) {
|
2005-09-02 19:15:44 +00:00
|
|
|
N->dump();
|
|
|
|
assert(0 && "Node is not in map!");
|
|
|
|
}
|
|
|
|
#endif
|
2005-01-07 21:09:16 +00:00
|
|
|
}
|
|
|
|
|
2005-08-17 19:00:20 +00:00
|
|
|
/// AddNonLeafNodeToCSEMaps - Add the specified node back to the CSE maps. It
|
|
|
|
/// has been taken out and modified in some way. If the specified node already
|
|
|
|
/// exists in the CSE maps, do not modify the maps, but return the existing node
|
|
|
|
/// instead. If it doesn't exist, add it and return null.
|
|
|
|
///
|
|
|
|
SDNode *SelectionDAG::AddNonLeafNodeToCSEMaps(SDNode *N) {
|
|
|
|
assert(N->getNumOperands() && "This is a leaf node!");
|
2006-01-29 07:58:15 +00:00
|
|
|
if (N->getOpcode() == ISD::HANDLENODE || N->getValueType(0) == MVT::Flag)
|
2005-12-01 23:14:50 +00:00
|
|
|
return 0; // Never add these nodes.
|
2005-11-30 18:20:52 +00:00
|
|
|
|
2005-12-19 22:21:21 +00:00
|
|
|
// Check that remaining values produced are not flags.
|
|
|
|
for (unsigned i = 1, e = N->getNumValues(); i != e; ++i)
|
|
|
|
if (N->getValueType(i) == MVT::Flag)
|
|
|
|
return 0; // Never CSE anything that produces a flag.
|
|
|
|
|
2005-12-01 23:14:50 +00:00
|
|
|
if (N->getNumValues() == 1) {
|
|
|
|
if (N->getNumOperands() == 1) {
|
|
|
|
SDNode *&U = UnaryOps[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(N->getOperand(0),
|
|
|
|
N->getValueType(0)))];
|
|
|
|
if (U) return U;
|
|
|
|
U = N;
|
|
|
|
} else if (N->getNumOperands() == 2) {
|
|
|
|
SDNode *&B = BinaryOps[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(N->getOperand(0),
|
|
|
|
N->getOperand(1)))];
|
|
|
|
if (B) return B;
|
|
|
|
B = N;
|
|
|
|
} else {
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
|
|
|
SDNode *&ORN = OneResultNodes[std::make_pair(N->getOpcode(),
|
2006-01-28 10:09:25 +00:00
|
|
|
std::make_pair(N->getValueType(0), Ops))];
|
2005-12-01 23:14:50 +00:00
|
|
|
if (ORN) return ORN;
|
|
|
|
ORN = N;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (N->getOpcode() == ISD::LOAD) {
|
|
|
|
SDNode *&L = Loads[std::make_pair(N->getOperand(1),
|
|
|
|
std::make_pair(N->getOperand(0),
|
|
|
|
N->getValueType(0)))];
|
|
|
|
if (L) return L;
|
|
|
|
L = N;
|
|
|
|
} else {
|
|
|
|
// Remove the node from the ArbitraryNodes map.
|
|
|
|
std::vector<MVT::ValueType> RV(N->value_begin(), N->value_end());
|
|
|
|
std::vector<SDOperand> Ops(N->op_begin(), N->op_end());
|
|
|
|
SDNode *&AN = ArbitraryNodes[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(RV, Ops))];
|
|
|
|
if (AN) return AN;
|
|
|
|
AN = N;
|
|
|
|
}
|
2005-08-17 19:00:20 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-01-28 09:32:45 +00:00
|
|
|
/// FindModifiedNodeSlot - Find a slot for the specified node if its operands
|
|
|
|
/// were replaced with those specified. If this node is never memoized,
|
|
|
|
/// return null, otherwise return a pointer to the slot it would take. If a
|
|
|
|
/// node already exists with these operands, the slot will be non-null.
|
|
|
|
SDNode **SelectionDAG::FindModifiedNodeSlot(SDNode *N, SDOperand Op) {
|
2006-01-29 07:58:15 +00:00
|
|
|
if (N->getOpcode() == ISD::HANDLENODE || N->getValueType(0) == MVT::Flag)
|
2006-01-28 09:32:45 +00:00
|
|
|
return 0; // Never add these nodes.
|
|
|
|
|
|
|
|
// Check that remaining values produced are not flags.
|
|
|
|
for (unsigned i = 1, e = N->getNumValues(); i != e; ++i)
|
|
|
|
if (N->getValueType(i) == MVT::Flag)
|
|
|
|
return 0; // Never CSE anything that produces a flag.
|
|
|
|
|
|
|
|
if (N->getNumValues() == 1) {
|
|
|
|
return &UnaryOps[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(Op, N->getValueType(0)))];
|
|
|
|
} else {
|
|
|
|
// Remove the node from the ArbitraryNodes map.
|
|
|
|
std::vector<MVT::ValueType> RV(N->value_begin(), N->value_end());
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op);
|
|
|
|
return &ArbitraryNodes[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(RV, Ops))];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// FindModifiedNodeSlot - Find a slot for the specified node if its operands
|
|
|
|
/// were replaced with those specified. If this node is never memoized,
|
|
|
|
/// return null, otherwise return a pointer to the slot it would take. If a
|
|
|
|
/// node already exists with these operands, the slot will be non-null.
|
|
|
|
SDNode **SelectionDAG::FindModifiedNodeSlot(SDNode *N,
|
|
|
|
SDOperand Op1, SDOperand Op2) {
|
2006-01-29 07:58:15 +00:00
|
|
|
if (N->getOpcode() == ISD::HANDLENODE || N->getValueType(0) == MVT::Flag)
|
2006-01-28 09:32:45 +00:00
|
|
|
return 0; // Never add these nodes.
|
|
|
|
|
|
|
|
// Check that remaining values produced are not flags.
|
|
|
|
for (unsigned i = 1, e = N->getNumValues(); i != e; ++i)
|
|
|
|
if (N->getValueType(i) == MVT::Flag)
|
|
|
|
return 0; // Never CSE anything that produces a flag.
|
|
|
|
|
|
|
|
if (N->getNumValues() == 1) {
|
|
|
|
return &BinaryOps[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(Op1, Op2))];
|
|
|
|
} else {
|
|
|
|
std::vector<MVT::ValueType> RV(N->value_begin(), N->value_end());
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op1);
|
|
|
|
Ops.push_back(Op2);
|
|
|
|
return &ArbitraryNodes[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(RV, Ops))];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// FindModifiedNodeSlot - Find a slot for the specified node if its operands
|
|
|
|
/// were replaced with those specified. If this node is never memoized,
|
|
|
|
/// return null, otherwise return a pointer to the slot it would take. If a
|
|
|
|
/// node already exists with these operands, the slot will be non-null.
|
|
|
|
SDNode **SelectionDAG::FindModifiedNodeSlot(SDNode *N,
|
|
|
|
const std::vector<SDOperand> &Ops) {
|
2006-01-29 07:58:15 +00:00
|
|
|
if (N->getOpcode() == ISD::HANDLENODE || N->getValueType(0) == MVT::Flag)
|
2006-01-28 09:32:45 +00:00
|
|
|
return 0; // Never add these nodes.
|
|
|
|
|
|
|
|
// Check that remaining values produced are not flags.
|
|
|
|
for (unsigned i = 1, e = N->getNumValues(); i != e; ++i)
|
|
|
|
if (N->getValueType(i) == MVT::Flag)
|
|
|
|
return 0; // Never CSE anything that produces a flag.
|
|
|
|
|
|
|
|
if (N->getNumValues() == 1) {
|
|
|
|
if (N->getNumOperands() == 1) {
|
|
|
|
return &UnaryOps[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(Ops[0],
|
|
|
|
N->getValueType(0)))];
|
|
|
|
} else if (N->getNumOperands() == 2) {
|
|
|
|
return &BinaryOps[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(Ops[0], Ops[1]))];
|
|
|
|
} else {
|
|
|
|
return &OneResultNodes[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(N->getValueType(0),
|
|
|
|
Ops))];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (N->getOpcode() == ISD::LOAD) {
|
|
|
|
return &Loads[std::make_pair(Ops[1],
|
|
|
|
std::make_pair(Ops[0], N->getValueType(0)))];
|
|
|
|
} else {
|
|
|
|
std::vector<MVT::ValueType> RV(N->value_begin(), N->value_end());
|
|
|
|
return &ArbitraryNodes[std::make_pair(N->getOpcode(),
|
|
|
|
std::make_pair(RV, Ops))];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-08-17 19:00:20 +00:00
|
|
|
|
2005-01-07 21:09:16 +00:00
|
|
|
|
2003-08-11 14:57:33 +00:00
|
|
|
SelectionDAG::~SelectionDAG() {
|
2005-11-09 23:47:37 +00:00
|
|
|
while (!AllNodes.empty()) {
|
|
|
|
SDNode *N = AllNodes.begin();
|
2005-11-08 22:07:03 +00:00
|
|
|
delete [] N->OperandList;
|
|
|
|
N->OperandList = 0;
|
|
|
|
N->NumOperands = 0;
|
2005-11-09 23:47:37 +00:00
|
|
|
AllNodes.pop_front();
|
2005-11-08 22:07:03 +00:00
|
|
|
}
|
2003-08-11 14:57:33 +00:00
|
|
|
}
|
|
|
|
|
2005-04-13 02:38:18 +00:00
|
|
|
SDOperand SelectionDAG::getZeroExtendInReg(SDOperand Op, MVT::ValueType VT) {
|
2005-04-13 19:41:05 +00:00
|
|
|
if (Op.getValueType() == VT) return Op;
|
2005-05-10 02:22:38 +00:00
|
|
|
int64_t Imm = ~0ULL >> (64-MVT::getSizeInBits(VT));
|
2005-04-13 02:38:18 +00:00
|
|
|
return getNode(ISD::AND, Op.getValueType(), Op,
|
|
|
|
getConstant(Imm, Op.getValueType()));
|
|
|
|
}
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
SDOperand SelectionDAG::getConstant(uint64_t Val, MVT::ValueType VT) {
|
|
|
|
assert(MVT::isInteger(VT) && "Cannot create FP integer constant!");
|
|
|
|
// Mask out any bits that are not valid for this constant.
|
2005-01-08 06:24:30 +00:00
|
|
|
if (VT != MVT::i64)
|
|
|
|
Val &= ((uint64_t)1 << MVT::getSizeInBits(VT)) - 1;
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
SDNode *&N = Constants[std::make_pair(Val, VT)];
|
|
|
|
if (N) return SDOperand(N, 0);
|
2005-08-17 00:34:06 +00:00
|
|
|
N = new ConstantSDNode(false, Val, VT);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2005-11-29 06:21:05 +00:00
|
|
|
SDOperand SelectionDAG::getString(const std::string &Val) {
|
|
|
|
StringSDNode *&N = StringNodes[Val];
|
|
|
|
if (!N) {
|
|
|
|
N = new StringSDNode(Val);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
}
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2005-08-17 00:34:06 +00:00
|
|
|
SDOperand SelectionDAG::getTargetConstant(uint64_t Val, MVT::ValueType VT) {
|
|
|
|
assert(MVT::isInteger(VT) && "Cannot create FP integer constant!");
|
|
|
|
// Mask out any bits that are not valid for this constant.
|
|
|
|
if (VT != MVT::i64)
|
|
|
|
Val &= ((uint64_t)1 << MVT::getSizeInBits(VT)) - 1;
|
|
|
|
|
|
|
|
SDNode *&N = TargetConstants[std::make_pair(Val, VT)];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
N = new ConstantSDNode(true, Val, VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
2003-08-11 14:57:33 +00:00
|
|
|
}
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
SDOperand SelectionDAG::getConstantFP(double Val, MVT::ValueType VT) {
|
|
|
|
assert(MVT::isFloatingPoint(VT) && "Cannot create integer FP constant!");
|
|
|
|
if (VT == MVT::f32)
|
|
|
|
Val = (float)Val; // Mask out extra precision.
|
|
|
|
|
2005-02-17 20:17:32 +00:00
|
|
|
// Do the map lookup using the actual bit pattern for the floating point
|
|
|
|
// value, so that we don't have problems with 0.0 comparing equal to -0.0, and
|
|
|
|
// we don't have issues with SNANs.
|
2005-08-17 19:34:49 +00:00
|
|
|
SDNode *&N = ConstantFPs[std::make_pair(DoubleToBits(Val), VT)];
|
2005-01-07 07:46:32 +00:00
|
|
|
if (N) return SDOperand(N, 0);
|
2006-01-29 06:26:56 +00:00
|
|
|
N = new ConstantFPSDNode(false, Val, VT);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getTargetConstantFP(double Val, MVT::ValueType VT) {
|
|
|
|
assert(MVT::isFloatingPoint(VT) && "Cannot create integer FP constant!");
|
|
|
|
if (VT == MVT::f32)
|
|
|
|
Val = (float)Val; // Mask out extra precision.
|
|
|
|
|
|
|
|
// Do the map lookup using the actual bit pattern for the floating point
|
|
|
|
// value, so that we don't have problems with 0.0 comparing equal to -0.0, and
|
|
|
|
// we don't have issues with SNANs.
|
|
|
|
SDNode *&N = TargetConstantFPs[std::make_pair(DoubleToBits(Val), VT)];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
N = new ConstantFPSDNode(true, Val, VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getGlobalAddress(const GlobalValue *GV,
|
2005-11-30 02:49:21 +00:00
|
|
|
MVT::ValueType VT, int offset) {
|
|
|
|
SDNode *&N = GlobalValues[std::make_pair(GV, offset)];
|
2005-01-07 07:46:32 +00:00
|
|
|
if (N) return SDOperand(N, 0);
|
2005-12-30 00:10:38 +00:00
|
|
|
N = new GlobalAddressSDNode(false, GV, VT, offset);
|
2005-08-19 22:31:04 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getTargetGlobalAddress(const GlobalValue *GV,
|
2005-11-30 02:04:11 +00:00
|
|
|
MVT::ValueType VT, int offset) {
|
2005-11-30 02:49:21 +00:00
|
|
|
SDNode *&N = TargetGlobalValues[std::make_pair(GV, offset)];
|
2005-08-19 22:31:04 +00:00
|
|
|
if (N) return SDOperand(N, 0);
|
2005-11-30 02:04:11 +00:00
|
|
|
N = new GlobalAddressSDNode(true, GV, VT, offset);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getFrameIndex(int FI, MVT::ValueType VT) {
|
|
|
|
SDNode *&N = FrameIndices[FI];
|
|
|
|
if (N) return SDOperand(N, 0);
|
2005-08-25 00:43:01 +00:00
|
|
|
N = new FrameIndexSDNode(FI, VT, false);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getTargetFrameIndex(int FI, MVT::ValueType VT) {
|
|
|
|
SDNode *&N = TargetFrameIndices[FI];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
N = new FrameIndexSDNode(FI, VT, true);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2006-01-31 22:23:14 +00:00
|
|
|
SDOperand SelectionDAG::getConstantPool(Constant *C, MVT::ValueType VT,
|
|
|
|
unsigned Alignment) {
|
|
|
|
SDNode *&N = ConstantPoolIndices[std::make_pair(C, Alignment)];
|
2005-01-07 07:46:32 +00:00
|
|
|
if (N) return SDOperand(N, 0);
|
2006-01-31 22:23:14 +00:00
|
|
|
N = new ConstantPoolSDNode(C, VT, Alignment, false);
|
2005-08-25 05:03:06 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2006-01-31 22:23:14 +00:00
|
|
|
SDOperand SelectionDAG::getTargetConstantPool(Constant *C, MVT::ValueType VT,
|
|
|
|
unsigned Alignment) {
|
|
|
|
SDNode *&N = TargetConstantPoolIndices[std::make_pair(C, Alignment)];
|
2005-08-25 05:03:06 +00:00
|
|
|
if (N) return SDOperand(N, 0);
|
2006-01-31 22:23:14 +00:00
|
|
|
N = new ConstantPoolSDNode(C, VT, Alignment, true);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getBasicBlock(MachineBasicBlock *MBB) {
|
|
|
|
SDNode *&N = BBNodes[MBB];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
N = new BasicBlockSDNode(MBB);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2005-07-10 00:07:11 +00:00
|
|
|
SDOperand SelectionDAG::getValueType(MVT::ValueType VT) {
|
|
|
|
if ((unsigned)VT >= ValueTypeNodes.size())
|
|
|
|
ValueTypeNodes.resize(VT+1);
|
|
|
|
if (ValueTypeNodes[VT] == 0) {
|
|
|
|
ValueTypeNodes[VT] = new VTSDNode(VT);
|
|
|
|
AllNodes.push_back(ValueTypeNodes[VT]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SDOperand(ValueTypeNodes[VT], 0);
|
|
|
|
}
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
SDOperand SelectionDAG::getExternalSymbol(const char *Sym, MVT::ValueType VT) {
|
|
|
|
SDNode *&N = ExternalSymbols[Sym];
|
|
|
|
if (N) return SDOperand(N, 0);
|
2005-10-23 03:40:17 +00:00
|
|
|
N = new ExternalSymbolSDNode(false, Sym, VT);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2006-01-28 10:09:25 +00:00
|
|
|
SDOperand SelectionDAG::getTargetExternalSymbol(const char *Sym,
|
|
|
|
MVT::ValueType VT) {
|
2005-10-23 03:40:17 +00:00
|
|
|
SDNode *&N = TargetExternalSymbols[Sym];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
N = new ExternalSymbolSDNode(true, Sym, VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2005-08-09 20:20:18 +00:00
|
|
|
SDOperand SelectionDAG::getCondCode(ISD::CondCode Cond) {
|
|
|
|
if ((unsigned)Cond >= CondCodeNodes.size())
|
|
|
|
CondCodeNodes.resize(Cond+1);
|
|
|
|
|
2005-08-09 20:40:02 +00:00
|
|
|
if (CondCodeNodes[Cond] == 0) {
|
2005-08-09 20:20:18 +00:00
|
|
|
CondCodeNodes[Cond] = new CondCodeSDNode(Cond);
|
2005-08-09 20:40:02 +00:00
|
|
|
AllNodes.push_back(CondCodeNodes[Cond]);
|
|
|
|
}
|
2005-08-09 20:20:18 +00:00
|
|
|
return SDOperand(CondCodeNodes[Cond], 0);
|
|
|
|
}
|
|
|
|
|
2005-08-30 22:38:38 +00:00
|
|
|
SDOperand SelectionDAG::getRegister(unsigned RegNo, MVT::ValueType VT) {
|
|
|
|
RegisterSDNode *&Reg = RegNodes[std::make_pair(RegNo, VT)];
|
|
|
|
if (!Reg) {
|
|
|
|
Reg = new RegisterSDNode(RegNo, VT);
|
|
|
|
AllNodes.push_back(Reg);
|
2005-08-16 21:55:35 +00:00
|
|
|
}
|
2005-08-30 22:38:38 +00:00
|
|
|
return SDOperand(Reg, 0);
|
2005-08-16 21:55:35 +00:00
|
|
|
}
|
|
|
|
|
2005-08-09 23:09:05 +00:00
|
|
|
SDOperand SelectionDAG::SimplifySetCC(MVT::ValueType VT, SDOperand N1,
|
|
|
|
SDOperand N2, ISD::CondCode Cond) {
|
2005-01-07 07:46:32 +00:00
|
|
|
// These setcc operations always fold.
|
|
|
|
switch (Cond) {
|
|
|
|
default: break;
|
|
|
|
case ISD::SETFALSE:
|
2005-01-18 02:52:03 +00:00
|
|
|
case ISD::SETFALSE2: return getConstant(0, VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
case ISD::SETTRUE:
|
2005-01-18 02:52:03 +00:00
|
|
|
case ISD::SETTRUE2: return getConstant(1, VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
if (ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2.Val)) {
|
|
|
|
uint64_t C2 = N2C->getValue();
|
|
|
|
if (ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.Val)) {
|
|
|
|
uint64_t C1 = N1C->getValue();
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
// Sign extend the operands if required
|
|
|
|
if (ISD::isSignedIntSetCC(Cond)) {
|
|
|
|
C1 = N1C->getSignExtended();
|
|
|
|
C2 = N2C->getSignExtended();
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Cond) {
|
|
|
|
default: assert(0 && "Unknown integer setcc!");
|
2005-01-18 02:52:03 +00:00
|
|
|
case ISD::SETEQ: return getConstant(C1 == C2, VT);
|
|
|
|
case ISD::SETNE: return getConstant(C1 != C2, VT);
|
|
|
|
case ISD::SETULT: return getConstant(C1 < C2, VT);
|
|
|
|
case ISD::SETUGT: return getConstant(C1 > C2, VT);
|
|
|
|
case ISD::SETULE: return getConstant(C1 <= C2, VT);
|
|
|
|
case ISD::SETUGE: return getConstant(C1 >= C2, VT);
|
|
|
|
case ISD::SETLT: return getConstant((int64_t)C1 < (int64_t)C2, VT);
|
|
|
|
case ISD::SETGT: return getConstant((int64_t)C1 > (int64_t)C2, VT);
|
|
|
|
case ISD::SETLE: return getConstant((int64_t)C1 <= (int64_t)C2, VT);
|
|
|
|
case ISD::SETGE: return getConstant((int64_t)C1 >= (int64_t)C2, VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
2005-04-07 18:58:54 +00:00
|
|
|
} else {
|
2005-08-24 22:44:39 +00:00
|
|
|
// If the LHS is a ZERO_EXTEND, perform the comparison on the input.
|
2005-04-18 04:30:45 +00:00
|
|
|
if (N1.getOpcode() == ISD::ZERO_EXTEND) {
|
|
|
|
unsigned InSize = MVT::getSizeInBits(N1.getOperand(0).getValueType());
|
|
|
|
|
|
|
|
// If the comparison constant has bits in the upper part, the
|
|
|
|
// zero-extended value could never match.
|
|
|
|
if (C2 & (~0ULL << InSize)) {
|
|
|
|
unsigned VSize = MVT::getSizeInBits(N1.getValueType());
|
|
|
|
switch (Cond) {
|
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETEQ: return getConstant(0, VT);
|
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETULE:
|
|
|
|
case ISD::SETNE: return getConstant(1, VT);
|
|
|
|
case ISD::SETGT:
|
|
|
|
case ISD::SETGE:
|
|
|
|
// True if the sign bit of C2 is set.
|
|
|
|
return getConstant((C2 & (1ULL << VSize)) != 0, VT);
|
|
|
|
case ISD::SETLT:
|
|
|
|
case ISD::SETLE:
|
|
|
|
// True if the sign bit of C2 isn't set.
|
|
|
|
return getConstant((C2 & (1ULL << VSize)) == 0, VT);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we can perform the comparison with the low bits.
|
|
|
|
switch (Cond) {
|
|
|
|
case ISD::SETEQ:
|
|
|
|
case ISD::SETNE:
|
|
|
|
case ISD::SETUGT:
|
|
|
|
case ISD::SETUGE:
|
|
|
|
case ISD::SETULT:
|
|
|
|
case ISD::SETULE:
|
2005-08-09 20:20:18 +00:00
|
|
|
return getSetCC(VT, N1.getOperand(0),
|
|
|
|
getConstant(C2, N1.getOperand(0).getValueType()),
|
|
|
|
Cond);
|
2005-04-18 04:30:45 +00:00
|
|
|
default:
|
|
|
|
break; // todo, be more careful with signed comparisons
|
|
|
|
}
|
2005-08-24 22:44:39 +00:00
|
|
|
} else if (N1.getOpcode() == ISD::SIGN_EXTEND_INREG &&
|
|
|
|
(Cond == ISD::SETEQ || Cond == ISD::SETNE)) {
|
|
|
|
MVT::ValueType ExtSrcTy = cast<VTSDNode>(N1.getOperand(1))->getVT();
|
|
|
|
unsigned ExtSrcTyBits = MVT::getSizeInBits(ExtSrcTy);
|
|
|
|
MVT::ValueType ExtDstTy = N1.getValueType();
|
|
|
|
unsigned ExtDstTyBits = MVT::getSizeInBits(ExtDstTy);
|
Add support for AssertSext and AssertZext, folding other extensions with
them. This allows for elminination of redundant extends in the entry
blocks of functions on PowerPC.
Add support for i32 x i32 -> i64 multiplies, by recognizing when the inputs
to ISD::MUL in ExpandOp are actually just extended i32 values and not real
i64 values. this allows us to codegen
int mulhs(int a, int b) { return ((long long)a * b) >> 32; }
as:
_mulhs:
mulhw r3, r4, r3
blr
instead of:
_mulhs:
mulhwu r2, r4, r3
srawi r5, r3, 31
mullw r5, r4, r5
add r2, r2, r5
srawi r4, r4, 31
mullw r3, r4, r3
add r3, r2, r3
blr
with a similar improvement on x86.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@23147 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-30 02:44:00 +00:00
|
|
|
|
2005-08-24 22:44:39 +00:00
|
|
|
// If the extended part has any inconsistent bits, it cannot ever
|
|
|
|
// compare equal. In other words, they have to be all ones or all
|
|
|
|
// zeros.
|
|
|
|
uint64_t ExtBits =
|
2005-08-31 02:47:06 +00:00
|
|
|
(~0ULL >> (64-ExtSrcTyBits)) & (~0ULL << (ExtDstTyBits-1));
|
2005-08-24 22:44:39 +00:00
|
|
|
if ((C2 & ExtBits) != 0 && (C2 & ExtBits) != ExtBits)
|
|
|
|
return getConstant(Cond == ISD::SETNE, VT);
|
|
|
|
|
|
|
|
// Otherwise, make this a use of a zext.
|
|
|
|
return getSetCC(VT, getZeroExtendInReg(N1.getOperand(0), ExtSrcTy),
|
2005-08-31 02:47:06 +00:00
|
|
|
getConstant(C2 & (~0ULL>>(64-ExtSrcTyBits)), ExtDstTy),
|
2005-08-24 22:44:39 +00:00
|
|
|
Cond);
|
2005-04-18 04:30:45 +00:00
|
|
|
}
|
|
|
|
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
uint64_t MinVal, MaxVal;
|
|
|
|
unsigned OperandBitSize = MVT::getSizeInBits(N2C->getValueType(0));
|
|
|
|
if (ISD::isSignedIntSetCC(Cond)) {
|
|
|
|
MinVal = 1ULL << (OperandBitSize-1);
|
|
|
|
if (OperandBitSize != 1) // Avoid X >> 64, which is undefined.
|
|
|
|
MaxVal = ~0ULL >> (65-OperandBitSize);
|
|
|
|
else
|
|
|
|
MaxVal = 0;
|
|
|
|
} else {
|
|
|
|
MinVal = 0;
|
|
|
|
MaxVal = ~0ULL >> (64-OperandBitSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Canonicalize GE/LE comparisons to use GT/LT comparisons.
|
|
|
|
if (Cond == ISD::SETGE || Cond == ISD::SETUGE) {
|
|
|
|
if (C2 == MinVal) return getConstant(1, VT); // X >= MIN --> true
|
|
|
|
--C2; // X >= C1 --> X > (C1-1)
|
2005-08-09 23:09:05 +00:00
|
|
|
return getSetCC(VT, N1, getConstant(C2, N2.getValueType()),
|
|
|
|
(Cond == ISD::SETGE) ? ISD::SETGT : ISD::SETUGT);
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Cond == ISD::SETLE || Cond == ISD::SETULE) {
|
|
|
|
if (C2 == MaxVal) return getConstant(1, VT); // X <= MAX --> true
|
|
|
|
++C2; // X <= C1 --> X < (C1+1)
|
2005-08-09 23:09:05 +00:00
|
|
|
return getSetCC(VT, N1, getConstant(C2, N2.getValueType()),
|
|
|
|
(Cond == ISD::SETLE) ? ISD::SETLT : ISD::SETULT);
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
}
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-04-14 08:56:52 +00:00
|
|
|
if ((Cond == ISD::SETLT || Cond == ISD::SETULT) && C2 == MinVal)
|
|
|
|
return getConstant(0, VT); // X < MIN --> false
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-04-14 08:56:52 +00:00
|
|
|
// Canonicalize setgt X, Min --> setne X, Min
|
|
|
|
if ((Cond == ISD::SETGT || Cond == ISD::SETUGT) && C2 == MinVal)
|
2005-08-09 20:20:18 +00:00
|
|
|
return getSetCC(VT, N1, N2, ISD::SETNE);
|
2005-04-21 22:36:52 +00:00
|
|
|
|
canonicalize x <u 1 -> x == 0. On this testcase:
unsigned long long g;
unsigned long foo (unsigned long a) {
return (a >= g) ? 1 : 0;
}
It changes the ppc code from:
_foo:
.LBB_foo_0: ; entry
mflr r11
stw r11, 8(r1)
bl "L00000$pb"
"L00000$pb":
mflr r2
addis r2, r2, ha16(L_g$non_lazy_ptr-"L00000$pb")
lwz r2, lo16(L_g$non_lazy_ptr-"L00000$pb")(r2)
lwz r4, 0(r2)
lwz r2, 4(r2)
cmplw cr0, r3, r2
li r2, 1
li r3, 0
bge .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
or r2, r3, r3
.LBB_foo_2: ; entry
cmplwi cr0, r4, 1
li r3, 1
li r5, 0
blt .LBB_foo_4 ; entry
.LBB_foo_3: ; entry
or r3, r5, r5
.LBB_foo_4: ; entry
cmpwi cr0, r4, 0
beq .LBB_foo_6 ; entry
.LBB_foo_5: ; entry
or r2, r3, r3
.LBB_foo_6: ; entry
rlwinm r3, r2, 0, 31, 31
lwz r11, 8(r1)
mtlr r11
blr
to:
_foo:
.LBB_foo_0: ; entry
mflr r11
stw r11, 8(r1)
bl "L00000$pb"
"L00000$pb":
mflr r2
addis r2, r2, ha16(L_g$non_lazy_ptr-"L00000$pb")
lwz r2, lo16(L_g$non_lazy_ptr-"L00000$pb")(r2)
lwz r4, 0(r2)
lwz r2, 4(r2)
cmplw cr0, r3, r2
li r2, 1
li r3, 0
bge .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
or r2, r3, r3
.LBB_foo_2: ; entry
cntlzw r3, r4
srwi r3, r3, 5
cmpwi cr0, r4, 0
beq .LBB_foo_4 ; entry
.LBB_foo_3: ; entry
or r2, r3, r3
.LBB_foo_4: ; entry
rlwinm r3, r2, 0, 31, 31
lwz r11, 8(r1)
mtlr r11
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21241 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-12 00:28:49 +00:00
|
|
|
// If we have setult X, 1, turn it into seteq X, 0
|
|
|
|
if ((Cond == ISD::SETLT || Cond == ISD::SETULT) && C2 == MinVal+1)
|
2005-08-09 20:20:18 +00:00
|
|
|
return getSetCC(VT, N1, getConstant(MinVal, N1.getValueType()),
|
|
|
|
ISD::SETEQ);
|
2005-04-14 08:56:52 +00:00
|
|
|
// If we have setugt X, Max-1, turn it into seteq X, Max
|
canonicalize x <u 1 -> x == 0. On this testcase:
unsigned long long g;
unsigned long foo (unsigned long a) {
return (a >= g) ? 1 : 0;
}
It changes the ppc code from:
_foo:
.LBB_foo_0: ; entry
mflr r11
stw r11, 8(r1)
bl "L00000$pb"
"L00000$pb":
mflr r2
addis r2, r2, ha16(L_g$non_lazy_ptr-"L00000$pb")
lwz r2, lo16(L_g$non_lazy_ptr-"L00000$pb")(r2)
lwz r4, 0(r2)
lwz r2, 4(r2)
cmplw cr0, r3, r2
li r2, 1
li r3, 0
bge .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
or r2, r3, r3
.LBB_foo_2: ; entry
cmplwi cr0, r4, 1
li r3, 1
li r5, 0
blt .LBB_foo_4 ; entry
.LBB_foo_3: ; entry
or r3, r5, r5
.LBB_foo_4: ; entry
cmpwi cr0, r4, 0
beq .LBB_foo_6 ; entry
.LBB_foo_5: ; entry
or r2, r3, r3
.LBB_foo_6: ; entry
rlwinm r3, r2, 0, 31, 31
lwz r11, 8(r1)
mtlr r11
blr
to:
_foo:
.LBB_foo_0: ; entry
mflr r11
stw r11, 8(r1)
bl "L00000$pb"
"L00000$pb":
mflr r2
addis r2, r2, ha16(L_g$non_lazy_ptr-"L00000$pb")
lwz r2, lo16(L_g$non_lazy_ptr-"L00000$pb")(r2)
lwz r4, 0(r2)
lwz r2, 4(r2)
cmplw cr0, r3, r2
li r2, 1
li r3, 0
bge .LBB_foo_2 ; entry
.LBB_foo_1: ; entry
or r2, r3, r3
.LBB_foo_2: ; entry
cntlzw r3, r4
srwi r3, r3, 5
cmpwi cr0, r4, 0
beq .LBB_foo_4 ; entry
.LBB_foo_3: ; entry
or r2, r3, r3
.LBB_foo_4: ; entry
rlwinm r3, r2, 0, 31, 31
lwz r11, 8(r1)
mtlr r11
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21241 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-12 00:28:49 +00:00
|
|
|
else if ((Cond == ISD::SETGT || Cond == ISD::SETUGT) && C2 == MaxVal-1)
|
2005-08-09 20:20:18 +00:00
|
|
|
return getSetCC(VT, N1, getConstant(MaxVal, N1.getValueType()),
|
|
|
|
ISD::SETEQ);
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
|
|
|
|
// If we have "setcc X, C1", check to see if we can shrink the immediate
|
|
|
|
// by changing cc.
|
|
|
|
|
|
|
|
// SETUGT X, SINTMAX -> SETLT X, 0
|
|
|
|
if (Cond == ISD::SETUGT && OperandBitSize != 1 &&
|
|
|
|
C2 == (~0ULL >> (65-OperandBitSize)))
|
2005-08-09 20:20:18 +00:00
|
|
|
return getSetCC(VT, N1, getConstant(0, N2.getValueType()), ISD::SETLT);
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
|
|
|
|
// FIXME: Implement the rest of these.
|
|
|
|
|
Fold (x & 8) != 0 and (x & 8) == 8 into (x & 8) >> 3.
This turns this PPC code:
rlwinm r2, r3, 0, 28, 28
cmpwi cr7, r2, 8
mfcr r2
rlwinm r3, r2, 31, 31, 31
into this:
rlwinm r2, r3, 0, 28, 28
srwi r2, r2, 3
rlwinm r3, r2, 0, 31, 31
Next up, nuking the extra and.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21390 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-21 06:12:41 +00:00
|
|
|
|
|
|
|
// Fold bit comparisons when we can.
|
|
|
|
if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) &&
|
|
|
|
VT == N1.getValueType() && N1.getOpcode() == ISD::AND)
|
|
|
|
if (ConstantSDNode *AndRHS =
|
|
|
|
dyn_cast<ConstantSDNode>(N1.getOperand(1))) {
|
|
|
|
if (Cond == ISD::SETNE && C2 == 0) {// (X & 8) != 0 --> (X & 8) >> 3
|
|
|
|
// Perform the xform if the AND RHS is a single bit.
|
|
|
|
if ((AndRHS->getValue() & (AndRHS->getValue()-1)) == 0) {
|
|
|
|
return getNode(ISD::SRL, VT, N1,
|
2005-08-02 19:26:06 +00:00
|
|
|
getConstant(Log2_64(AndRHS->getValue()),
|
Fold (x & 8) != 0 and (x & 8) == 8 into (x & 8) >> 3.
This turns this PPC code:
rlwinm r2, r3, 0, 28, 28
cmpwi cr7, r2, 8
mfcr r2
rlwinm r3, r2, 31, 31, 31
into this:
rlwinm r2, r3, 0, 28, 28
srwi r2, r2, 3
rlwinm r3, r2, 0, 31, 31
Next up, nuking the extra and.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21390 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-21 06:12:41 +00:00
|
|
|
TLI.getShiftAmountTy()));
|
|
|
|
}
|
|
|
|
} else if (Cond == ISD::SETEQ && C2 == AndRHS->getValue()) {
|
|
|
|
// (X & 8) == 8 --> (X & 8) >> 3
|
|
|
|
// Perform the xform if C2 is a single bit.
|
|
|
|
if ((C2 & (C2-1)) == 0) {
|
|
|
|
return getNode(ISD::SRL, VT, N1,
|
2005-08-02 19:26:06 +00:00
|
|
|
getConstant(Log2_64(C2),TLI.getShiftAmountTy()));
|
Fold (x & 8) != 0 and (x & 8) == 8 into (x & 8) >> 3.
This turns this PPC code:
rlwinm r2, r3, 0, 28, 28
cmpwi cr7, r2, 8
mfcr r2
rlwinm r3, r2, 31, 31, 31
into this:
rlwinm r2, r3, 0, 28, 28
srwi r2, r2, 3
rlwinm r3, r2, 0, 31, 31
Next up, nuking the extra and.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21390 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-21 06:12:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
} else if (isa<ConstantSDNode>(N1.Val)) {
|
|
|
|
// Ensure that the constant occurs on the RHS.
|
2005-08-09 20:20:18 +00:00
|
|
|
return getSetCC(VT, N2, N1, ISD::getSetCCSwappedOperands(Cond));
|
This patch does two things. First, it canonicalizes 'X >= C' -> 'X > C-1'
(likewise for <= >=u >=u).
Second, it implements a special case hack to turn 'X gtu SINTMAX' -> 'X lt 0'
On powerpc, for example, this changes this:
lis r2, 32767
ori r2, r2, 65535
cmplw cr0, r3, r2
bgt .LBB_test_2
into:
cmpwi cr0, r3, 0
blt .LBB_test_2
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21142 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 18:14:58 +00:00
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
|
|
|
|
if (ConstantFPSDNode *N1C = dyn_cast<ConstantFPSDNode>(N1.Val))
|
|
|
|
if (ConstantFPSDNode *N2C = dyn_cast<ConstantFPSDNode>(N2.Val)) {
|
|
|
|
double C1 = N1C->getValue(), C2 = N2C->getValue();
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
switch (Cond) {
|
|
|
|
default: break; // FIXME: Implement the rest of these!
|
2005-01-18 02:52:03 +00:00
|
|
|
case ISD::SETEQ: return getConstant(C1 == C2, VT);
|
|
|
|
case ISD::SETNE: return getConstant(C1 != C2, VT);
|
|
|
|
case ISD::SETLT: return getConstant(C1 < C2, VT);
|
|
|
|
case ISD::SETGT: return getConstant(C1 > C2, VT);
|
|
|
|
case ISD::SETLE: return getConstant(C1 <= C2, VT);
|
|
|
|
case ISD::SETGE: return getConstant(C1 >= C2, VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Ensure that the constant occurs on the RHS.
|
2005-08-09 23:09:05 +00:00
|
|
|
return getSetCC(VT, N2, N1, ISD::getSetCCSwappedOperands(Cond));
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
2005-08-09 20:20:18 +00:00
|
|
|
// Could not fold it.
|
|
|
|
return SDOperand();
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getNode - Gets or creates the specified node.
|
2003-08-11 14:57:33 +00:00
|
|
|
///
|
2005-01-07 07:46:32 +00:00
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT) {
|
2005-09-02 19:36:17 +00:00
|
|
|
SDNode *&N = NullaryOps[std::make_pair(Opcode, VT)];
|
|
|
|
if (!N) {
|
|
|
|
N = new SDNode(Opcode, VT);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
|
|
|
|
SDOperand Operand) {
|
2006-01-16 08:07:10 +00:00
|
|
|
unsigned Tmp1;
|
constant fold bits_convert in getNode and in the dag combiner for fp<->int
conversions. This allows V8 to compiles this:
void %test() {
call float %test2( float 1.000000e+00, float 2.000000e+00, double 3.000000e+00, double* null )
ret void
}
into:
test:
save -96, %o6, %o6
sethi 0, %o3
sethi 1049088, %o2
sethi 1048576, %o1
sethi 1040384, %o0
or %g0, %o3, %o4
call test2
nop
restore %g0, %g0, %g0
retl
nop
instead of:
test:
save -112, %o6, %o6
sethi 0, %o4
sethi 1049088, %l0
st %o4, [%i6+-12]
st %l0, [%i6+-16]
ld [%i6+-12], %o3
ld [%i6+-16], %o2
sethi 1048576, %o1
sethi 1040384, %o0
call test2
nop
restore %g0, %g0, %g0
retl
nop
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24980 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-23 05:30:37 +00:00
|
|
|
// Constant fold unary operations with an integer constant operand.
|
2005-01-07 07:46:32 +00:00
|
|
|
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Operand.Val)) {
|
|
|
|
uint64_t Val = C->getValue();
|
|
|
|
switch (Opcode) {
|
|
|
|
default: break;
|
|
|
|
case ISD::SIGN_EXTEND: return getConstant(C->getSignExtended(), VT);
|
2005-09-02 00:17:32 +00:00
|
|
|
case ISD::ANY_EXTEND:
|
2005-01-07 07:46:32 +00:00
|
|
|
case ISD::ZERO_EXTEND: return getConstant(Val, VT);
|
|
|
|
case ISD::TRUNCATE: return getConstant(Val, VT);
|
2005-01-08 08:08:56 +00:00
|
|
|
case ISD::SINT_TO_FP: return getConstantFP(C->getSignExtended(), VT);
|
|
|
|
case ISD::UINT_TO_FP: return getConstantFP(C->getValue(), VT);
|
constant fold bits_convert in getNode and in the dag combiner for fp<->int
conversions. This allows V8 to compiles this:
void %test() {
call float %test2( float 1.000000e+00, float 2.000000e+00, double 3.000000e+00, double* null )
ret void
}
into:
test:
save -96, %o6, %o6
sethi 0, %o3
sethi 1049088, %o2
sethi 1048576, %o1
sethi 1040384, %o0
or %g0, %o3, %o4
call test2
nop
restore %g0, %g0, %g0
retl
nop
instead of:
test:
save -112, %o6, %o6
sethi 0, %o4
sethi 1049088, %l0
st %o4, [%i6+-12]
st %l0, [%i6+-16]
ld [%i6+-12], %o3
ld [%i6+-16], %o2
sethi 1048576, %o1
sethi 1040384, %o0
call test2
nop
restore %g0, %g0, %g0
retl
nop
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24980 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-23 05:30:37 +00:00
|
|
|
case ISD::BIT_CONVERT:
|
|
|
|
if (VT == MVT::f32) {
|
|
|
|
assert(C->getValueType(0) == MVT::i32 && "Invalid bit_convert!");
|
|
|
|
return getConstantFP(BitsToFloat(Val), VT);
|
|
|
|
} else if (VT == MVT::f64) {
|
|
|
|
assert(C->getValueType(0) == MVT::i64 && "Invalid bit_convert!");
|
|
|
|
return getConstantFP(BitsToDouble(Val), VT);
|
|
|
|
}
|
|
|
|
break;
|
2006-01-16 08:07:10 +00:00
|
|
|
case ISD::BSWAP:
|
|
|
|
switch(VT) {
|
|
|
|
default: assert(0 && "Invalid bswap!"); break;
|
|
|
|
case MVT::i16: return getConstant(ByteSwap_16((unsigned short)Val), VT);
|
|
|
|
case MVT::i32: return getConstant(ByteSwap_32((unsigned)Val), VT);
|
|
|
|
case MVT::i64: return getConstant(ByteSwap_64(Val), VT);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ISD::CTPOP:
|
|
|
|
switch(VT) {
|
|
|
|
default: assert(0 && "Invalid ctpop!"); break;
|
|
|
|
case MVT::i1: return getConstant(Val != 0, VT);
|
|
|
|
case MVT::i8:
|
|
|
|
Tmp1 = (unsigned)Val & 0xFF;
|
|
|
|
return getConstant(CountPopulation_32(Tmp1), VT);
|
|
|
|
case MVT::i16:
|
|
|
|
Tmp1 = (unsigned)Val & 0xFFFF;
|
|
|
|
return getConstant(CountPopulation_32(Tmp1), VT);
|
|
|
|
case MVT::i32:
|
|
|
|
return getConstant(CountPopulation_32((unsigned)Val), VT);
|
|
|
|
case MVT::i64:
|
|
|
|
return getConstant(CountPopulation_64(Val), VT);
|
|
|
|
}
|
|
|
|
case ISD::CTLZ:
|
|
|
|
switch(VT) {
|
|
|
|
default: assert(0 && "Invalid ctlz!"); break;
|
|
|
|
case MVT::i1: return getConstant(Val == 0, VT);
|
|
|
|
case MVT::i8:
|
|
|
|
Tmp1 = (unsigned)Val & 0xFF;
|
|
|
|
return getConstant(CountLeadingZeros_32(Tmp1)-24, VT);
|
|
|
|
case MVT::i16:
|
|
|
|
Tmp1 = (unsigned)Val & 0xFFFF;
|
|
|
|
return getConstant(CountLeadingZeros_32(Tmp1)-16, VT);
|
|
|
|
case MVT::i32:
|
|
|
|
return getConstant(CountLeadingZeros_32((unsigned)Val), VT);
|
|
|
|
case MVT::i64:
|
|
|
|
return getConstant(CountLeadingZeros_64(Val), VT);
|
|
|
|
}
|
|
|
|
case ISD::CTTZ:
|
|
|
|
switch(VT) {
|
|
|
|
default: assert(0 && "Invalid cttz!"); break;
|
|
|
|
case MVT::i1: return getConstant(Val == 0, VT);
|
|
|
|
case MVT::i8:
|
|
|
|
Tmp1 = (unsigned)Val | 0x100;
|
|
|
|
return getConstant(CountTrailingZeros_32(Tmp1), VT);
|
|
|
|
case MVT::i16:
|
|
|
|
Tmp1 = (unsigned)Val | 0x10000;
|
|
|
|
return getConstant(CountTrailingZeros_32(Tmp1), VT);
|
|
|
|
case MVT::i32:
|
|
|
|
return getConstant(CountTrailingZeros_32((unsigned)Val), VT);
|
|
|
|
case MVT::i64:
|
|
|
|
return getConstant(CountTrailingZeros_64(Val), VT);
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
constant fold bits_convert in getNode and in the dag combiner for fp<->int
conversions. This allows V8 to compiles this:
void %test() {
call float %test2( float 1.000000e+00, float 2.000000e+00, double 3.000000e+00, double* null )
ret void
}
into:
test:
save -96, %o6, %o6
sethi 0, %o3
sethi 1049088, %o2
sethi 1048576, %o1
sethi 1040384, %o0
or %g0, %o3, %o4
call test2
nop
restore %g0, %g0, %g0
retl
nop
instead of:
test:
save -112, %o6, %o6
sethi 0, %o4
sethi 1049088, %l0
st %o4, [%i6+-12]
st %l0, [%i6+-16]
ld [%i6+-12], %o3
ld [%i6+-16], %o2
sethi 1048576, %o1
sethi 1040384, %o0
call test2
nop
restore %g0, %g0, %g0
retl
nop
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24980 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-23 05:30:37 +00:00
|
|
|
// Constant fold unary operations with an floating point constant operand.
|
2005-01-07 07:46:32 +00:00
|
|
|
if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Operand.Val))
|
|
|
|
switch (Opcode) {
|
2005-04-09 03:02:46 +00:00
|
|
|
case ISD::FNEG:
|
|
|
|
return getConstantFP(-C->getValue(), VT);
|
constant fold bits_convert in getNode and in the dag combiner for fp<->int
conversions. This allows V8 to compiles this:
void %test() {
call float %test2( float 1.000000e+00, float 2.000000e+00, double 3.000000e+00, double* null )
ret void
}
into:
test:
save -96, %o6, %o6
sethi 0, %o3
sethi 1049088, %o2
sethi 1048576, %o1
sethi 1040384, %o0
or %g0, %o3, %o4
call test2
nop
restore %g0, %g0, %g0
retl
nop
instead of:
test:
save -112, %o6, %o6
sethi 0, %o4
sethi 1049088, %l0
st %o4, [%i6+-12]
st %l0, [%i6+-16]
ld [%i6+-12], %o3
ld [%i6+-16], %o2
sethi 1048576, %o1
sethi 1040384, %o0
call test2
nop
restore %g0, %g0, %g0
retl
nop
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24980 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-23 05:30:37 +00:00
|
|
|
case ISD::FABS:
|
|
|
|
return getConstantFP(fabs(C->getValue()), VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
case ISD::FP_ROUND:
|
|
|
|
case ISD::FP_EXTEND:
|
|
|
|
return getConstantFP(C->getValue(), VT);
|
2005-01-08 08:08:56 +00:00
|
|
|
case ISD::FP_TO_SINT:
|
|
|
|
return getConstant((int64_t)C->getValue(), VT);
|
|
|
|
case ISD::FP_TO_UINT:
|
|
|
|
return getConstant((uint64_t)C->getValue(), VT);
|
constant fold bits_convert in getNode and in the dag combiner for fp<->int
conversions. This allows V8 to compiles this:
void %test() {
call float %test2( float 1.000000e+00, float 2.000000e+00, double 3.000000e+00, double* null )
ret void
}
into:
test:
save -96, %o6, %o6
sethi 0, %o3
sethi 1049088, %o2
sethi 1048576, %o1
sethi 1040384, %o0
or %g0, %o3, %o4
call test2
nop
restore %g0, %g0, %g0
retl
nop
instead of:
test:
save -112, %o6, %o6
sethi 0, %o4
sethi 1049088, %l0
st %o4, [%i6+-12]
st %l0, [%i6+-16]
ld [%i6+-12], %o3
ld [%i6+-16], %o2
sethi 1048576, %o1
sethi 1040384, %o0
call test2
nop
restore %g0, %g0, %g0
retl
nop
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24980 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-23 05:30:37 +00:00
|
|
|
case ISD::BIT_CONVERT:
|
|
|
|
if (VT == MVT::i32) {
|
|
|
|
assert(C->getValueType(0) == MVT::f32 && "Invalid bit_convert!");
|
|
|
|
return getConstant(FloatToBits(C->getValue()), VT);
|
|
|
|
} else if (VT == MVT::i64) {
|
|
|
|
assert(C->getValueType(0) == MVT::f64 && "Invalid bit_convert!");
|
|
|
|
return getConstant(DoubleToBits(C->getValue()), VT);
|
|
|
|
}
|
|
|
|
break;
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned OpOpcode = Operand.Val->getOpcode();
|
|
|
|
switch (Opcode) {
|
2005-01-21 18:01:22 +00:00
|
|
|
case ISD::TokenFactor:
|
|
|
|
return Operand; // Factor of one node? No factor.
|
2005-01-07 07:46:32 +00:00
|
|
|
case ISD::SIGN_EXTEND:
|
|
|
|
if (Operand.getValueType() == VT) return Operand; // noop extension
|
|
|
|
if (OpOpcode == ISD::SIGN_EXTEND || OpOpcode == ISD::ZERO_EXTEND)
|
|
|
|
return getNode(OpOpcode, VT, Operand.Val->getOperand(0));
|
|
|
|
break;
|
|
|
|
case ISD::ZERO_EXTEND:
|
|
|
|
if (Operand.getValueType() == VT) return Operand; // noop extension
|
If a target zero or sign extends the result of its setcc, allow folding of
this into sign/zero extension instructions later.
On PPC, for example, this testcase:
%G = external global sbyte
implementation
void %test(int %X, int %Y) {
%C = setlt int %X, %Y
%D = cast bool %C to sbyte
store sbyte %D, sbyte* %G
ret void
}
Now codegens to:
cmpw cr0, r3, r4
li r3, 1
li r4, 0
blt .LBB_test_2 ;
.LBB_test_1: ;
or r3, r4, r4
.LBB_test_2: ;
addis r2, r2, ha16(L_G$non_lazy_ptr-"L00000$pb")
lwz r2, lo16(L_G$non_lazy_ptr-"L00000$pb")(r2)
stb r3, 0(r2)
instead of:
cmpw cr0, r3, r4
li r3, 1
li r4, 0
blt .LBB_test_2 ;
.LBB_test_1: ;
or r3, r4, r4
.LBB_test_2: ;
*** rlwinm r3, r3, 0, 31, 31
addis r2, r2, ha16(L_G$non_lazy_ptr-"L00000$pb")
lwz r2, lo16(L_G$non_lazy_ptr-"L00000$pb")(r2)
stb r3, 0(r2)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21148 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-07 19:43:53 +00:00
|
|
|
if (OpOpcode == ISD::ZERO_EXTEND) // (zext (zext x)) -> (zext x)
|
2005-01-12 18:51:15 +00:00
|
|
|
return getNode(ISD::ZERO_EXTEND, VT, Operand.Val->getOperand(0));
|
2005-01-07 07:46:32 +00:00
|
|
|
break;
|
2005-09-02 00:17:32 +00:00
|
|
|
case ISD::ANY_EXTEND:
|
|
|
|
if (Operand.getValueType() == VT) return Operand; // noop extension
|
|
|
|
if (OpOpcode == ISD::ZERO_EXTEND || OpOpcode == ISD::SIGN_EXTEND)
|
|
|
|
// (ext (zext x)) -> (zext x) and (ext (sext x)) -> (sext x)
|
|
|
|
return getNode(OpOpcode, VT, Operand.Val->getOperand(0));
|
|
|
|
break;
|
2005-01-07 07:46:32 +00:00
|
|
|
case ISD::TRUNCATE:
|
|
|
|
if (Operand.getValueType() == VT) return Operand; // noop truncate
|
|
|
|
if (OpOpcode == ISD::TRUNCATE)
|
|
|
|
return getNode(ISD::TRUNCATE, VT, Operand.Val->getOperand(0));
|
2005-09-02 00:17:32 +00:00
|
|
|
else if (OpOpcode == ISD::ZERO_EXTEND || OpOpcode == ISD::SIGN_EXTEND ||
|
|
|
|
OpOpcode == ISD::ANY_EXTEND) {
|
2005-01-07 21:56:24 +00:00
|
|
|
// If the source is smaller than the dest, we still need an extend.
|
|
|
|
if (Operand.Val->getOperand(0).getValueType() < VT)
|
|
|
|
return getNode(OpOpcode, VT, Operand.Val->getOperand(0));
|
|
|
|
else if (Operand.Val->getOperand(0).getValueType() > VT)
|
|
|
|
return getNode(ISD::TRUNCATE, VT, Operand.Val->getOperand(0));
|
|
|
|
else
|
|
|
|
return Operand.Val->getOperand(0);
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
break;
|
2005-12-23 00:16:34 +00:00
|
|
|
case ISD::BIT_CONVERT:
|
|
|
|
// Basic sanity checking.
|
|
|
|
assert(MVT::getSizeInBits(VT)==MVT::getSizeInBits(Operand.getValueType()) &&
|
|
|
|
"Cannot BIT_CONVERT between two different types!");
|
|
|
|
if (VT == Operand.getValueType()) return Operand; // noop conversion.
|
Fold bitconv(bitconv(x)) -> x. We now compile this:
void foo(double);
void bar(double X) { foo(X); }
to this:
bar:
save -96, %o6, %o6
or %g0, %i0, %o0
or %g0, %i1, %o1
call foo
nop
restore %g0, %g0, %g0
retl
nop
instead of this:
bar:
save -112, %o6, %o6
st %i1, [%i6+-4]
st %i0, [%i6+-8]
ldd [%i6+-8], %f0
std %f0, [%i6+-16]
ld [%i6+-12], %o1
ld [%i6+-16], %o0
call foo
nop
restore %g0, %g0, %g0
retl
nop
on V8.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24981 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-23 05:37:50 +00:00
|
|
|
if (OpOpcode == ISD::BIT_CONVERT) // bitconv(bitconv(x)) -> bitconv(x)
|
|
|
|
return getNode(ISD::BIT_CONVERT, VT, Operand.getOperand(0));
|
2005-12-23 00:16:34 +00:00
|
|
|
break;
|
2005-04-09 03:02:46 +00:00
|
|
|
case ISD::FNEG:
|
2005-09-28 22:28:18 +00:00
|
|
|
if (OpOpcode == ISD::FSUB) // -(X-Y) -> (Y-X)
|
|
|
|
return getNode(ISD::FSUB, VT, Operand.Val->getOperand(1),
|
2005-04-09 03:02:46 +00:00
|
|
|
Operand.Val->getOperand(0));
|
|
|
|
if (OpOpcode == ISD::FNEG) // --X -> X
|
|
|
|
return Operand.Val->getOperand(0);
|
|
|
|
break;
|
|
|
|
case ISD::FABS:
|
|
|
|
if (OpOpcode == ISD::FNEG) // abs(-X) -> abs(X)
|
|
|
|
return getNode(ISD::FABS, VT, Operand.Val->getOperand(0));
|
|
|
|
break;
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
2005-08-25 19:12:10 +00:00
|
|
|
SDNode *N;
|
|
|
|
if (VT != MVT::Flag) { // Don't CSE flag producing nodes
|
|
|
|
SDNode *&E = UnaryOps[std::make_pair(Opcode, std::make_pair(Operand, VT))];
|
2005-08-26 00:13:12 +00:00
|
|
|
if (E) return SDOperand(E, 0);
|
2005-08-25 19:12:10 +00:00
|
|
|
E = N = new SDNode(Opcode, Operand);
|
|
|
|
} else {
|
|
|
|
N = new SDNode(Opcode, Operand);
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
N->setValueTypes(VT);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
Make the AND elimination operation recursive and significantly more powerful,
eliminating an and for Nate's testcase:
int %bar(int %a, int %b) {
entry:
%tmp.1 = setne int %a, 0
%tmp.2 = setne int %b, 0
%tmp.3 = or bool %tmp.1, %tmp.2
%retval = cast bool %tmp.3 to int
ret int %retval
}
generating:
_bar:
addic r2, r3, -1
subfe r2, r2, r3
addic r3, r4, -1
subfe r3, r3, r4
or r3, r2, r3
blr
instead of:
_bar:
addic r2, r3, -1
subfe r2, r2, r3
addic r3, r4, -1
subfe r3, r3, r4
or r2, r2, r3
rlwinm r3, r2, 0, 31, 31
blr
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@21315 91177308-0d34-0410-b5e6-96231b3b80d8
2005-04-18 03:48:41 +00:00
|
|
|
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
|
|
|
|
SDOperand N1, SDOperand N2) {
|
2005-01-16 02:23:22 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
switch (Opcode) {
|
2005-01-19 18:01:40 +00:00
|
|
|
case ISD::TokenFactor:
|
|
|
|
assert(VT == MVT::Other && N1.getValueType() == MVT::Other &&
|
|
|
|
N2.getValueType() == MVT::Other && "Invalid token factor!");
|
|
|
|
break;
|
2005-01-16 02:23:22 +00:00
|
|
|
case ISD::AND:
|
|
|
|
case ISD::OR:
|
|
|
|
case ISD::XOR:
|
|
|
|
case ISD::UDIV:
|
|
|
|
case ISD::UREM:
|
Add some simplifications for MULH[SU]. This allows us to compile this:
long %bar(long %X) {
%Y = mul long %X, 4294967297
ret long %Y
}
to this:
l1_bar:
mov %EAX, DWORD PTR [%ESP + 4]
mov %EDX, %EAX
add %EDX, DWORD PTR [%ESP + 8]
ret
instead of:
l1_bar:
mov %ECX, DWORD PTR [%ESP + 4]
mov %EDX, 1
mov %EAX, %ECX
mul %EDX
add %EDX, %ECX
add %EDX, DWORD PTR [%ESP + 8]
mov %EAX, %ECX
ret
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22044 91177308-0d34-0410-b5e6-96231b3b80d8
2005-05-15 05:39:08 +00:00
|
|
|
case ISD::MULHU:
|
|
|
|
case ISD::MULHS:
|
2005-01-16 02:23:22 +00:00
|
|
|
assert(MVT::isInteger(VT) && "This operator does not apply to FP types!");
|
|
|
|
// fall through
|
|
|
|
case ISD::ADD:
|
|
|
|
case ISD::SUB:
|
|
|
|
case ISD::MUL:
|
|
|
|
case ISD::SDIV:
|
|
|
|
case ISD::SREM:
|
2005-09-28 22:28:18 +00:00
|
|
|
assert(MVT::isInteger(N1.getValueType()) && "Should use F* for FP ops");
|
|
|
|
// fall through.
|
|
|
|
case ISD::FADD:
|
|
|
|
case ISD::FSUB:
|
|
|
|
case ISD::FMUL:
|
|
|
|
case ISD::FDIV:
|
|
|
|
case ISD::FREM:
|
2005-01-16 02:23:22 +00:00
|
|
|
assert(N1.getValueType() == N2.getValueType() &&
|
|
|
|
N1.getValueType() == VT && "Binary operator types must match!");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ISD::SHL:
|
|
|
|
case ISD::SRA:
|
|
|
|
case ISD::SRL:
|
2006-01-11 21:21:00 +00:00
|
|
|
case ISD::ROTL:
|
|
|
|
case ISD::ROTR:
|
2005-01-16 02:23:22 +00:00
|
|
|
assert(VT == N1.getValueType() &&
|
|
|
|
"Shift operators return type must be the same as their first arg");
|
|
|
|
assert(MVT::isInteger(VT) && MVT::isInteger(N2.getValueType()) &&
|
2005-01-17 17:15:02 +00:00
|
|
|
VT != MVT::i1 && "Shifts only work on integers");
|
2005-01-16 02:23:22 +00:00
|
|
|
break;
|
2005-07-10 00:07:11 +00:00
|
|
|
case ISD::FP_ROUND_INREG: {
|
|
|
|
MVT::ValueType EVT = cast<VTSDNode>(N2)->getVT();
|
|
|
|
assert(VT == N1.getValueType() && "Not an inreg round!");
|
|
|
|
assert(MVT::isFloatingPoint(VT) && MVT::isFloatingPoint(EVT) &&
|
|
|
|
"Cannot FP_ROUND_INREG integer types");
|
|
|
|
assert(EVT <= VT && "Not rounding down!");
|
|
|
|
break;
|
|
|
|
}
|
Add support for AssertSext and AssertZext, folding other extensions with
them. This allows for elminination of redundant extends in the entry
blocks of functions on PowerPC.
Add support for i32 x i32 -> i64 multiplies, by recognizing when the inputs
to ISD::MUL in ExpandOp are actually just extended i32 values and not real
i64 values. this allows us to codegen
int mulhs(int a, int b) { return ((long long)a * b) >> 32; }
as:
_mulhs:
mulhw r3, r4, r3
blr
instead of:
_mulhs:
mulhwu r2, r4, r3
srawi r5, r3, 31
mullw r5, r4, r5
add r2, r2, r5
srawi r4, r4, 31
mullw r3, r4, r3
add r3, r2, r3
blr
with a similar improvement on x86.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@23147 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-30 02:44:00 +00:00
|
|
|
case ISD::AssertSext:
|
|
|
|
case ISD::AssertZext:
|
2005-07-10 00:07:11 +00:00
|
|
|
case ISD::SIGN_EXTEND_INREG: {
|
|
|
|
MVT::ValueType EVT = cast<VTSDNode>(N2)->getVT();
|
|
|
|
assert(VT == N1.getValueType() && "Not an inreg extend!");
|
|
|
|
assert(MVT::isInteger(VT) && MVT::isInteger(EVT) &&
|
|
|
|
"Cannot *_EXTEND_INREG FP types");
|
|
|
|
assert(EVT <= VT && "Not extending!");
|
|
|
|
}
|
|
|
|
|
2005-01-16 02:23:22 +00:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.Val);
|
|
|
|
ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2.Val);
|
|
|
|
if (N1C) {
|
|
|
|
if (N2C) {
|
|
|
|
uint64_t C1 = N1C->getValue(), C2 = N2C->getValue();
|
|
|
|
switch (Opcode) {
|
|
|
|
case ISD::ADD: return getConstant(C1 + C2, VT);
|
|
|
|
case ISD::SUB: return getConstant(C1 - C2, VT);
|
|
|
|
case ISD::MUL: return getConstant(C1 * C2, VT);
|
|
|
|
case ISD::UDIV:
|
|
|
|
if (C2) return getConstant(C1 / C2, VT);
|
|
|
|
break;
|
|
|
|
case ISD::UREM :
|
|
|
|
if (C2) return getConstant(C1 % C2, VT);
|
|
|
|
break;
|
|
|
|
case ISD::SDIV :
|
|
|
|
if (C2) return getConstant(N1C->getSignExtended() /
|
|
|
|
N2C->getSignExtended(), VT);
|
|
|
|
break;
|
|
|
|
case ISD::SREM :
|
|
|
|
if (C2) return getConstant(N1C->getSignExtended() %
|
|
|
|
N2C->getSignExtended(), VT);
|
|
|
|
break;
|
|
|
|
case ISD::AND : return getConstant(C1 & C2, VT);
|
|
|
|
case ISD::OR : return getConstant(C1 | C2, VT);
|
|
|
|
case ISD::XOR : return getConstant(C1 ^ C2, VT);
|
2005-08-31 00:27:53 +00:00
|
|
|
case ISD::SHL : return getConstant(C1 << C2, VT);
|
|
|
|
case ISD::SRL : return getConstant(C1 >> C2, VT);
|
2005-01-10 00:07:15 +00:00
|
|
|
case ISD::SRA : return getConstant(N1C->getSignExtended() >>(int)C2, VT);
|
2006-01-11 21:21:00 +00:00
|
|
|
case ISD::ROTL :
|
|
|
|
return getConstant((C1 << C2) | (C1 >> (MVT::getSizeInBits(VT) - C2)),
|
|
|
|
VT);
|
|
|
|
case ISD::ROTR :
|
|
|
|
return getConstant((C1 >> C2) | (C1 << (MVT::getSizeInBits(VT) - C2)),
|
|
|
|
VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
} else { // Cannonicalize constant to RHS if commutative
|
|
|
|
if (isCommutativeBinOp(Opcode)) {
|
|
|
|
std::swap(N1C, N2C);
|
|
|
|
std::swap(N1, N2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ConstantFPSDNode *N1CFP = dyn_cast<ConstantFPSDNode>(N1.Val);
|
|
|
|
ConstantFPSDNode *N2CFP = dyn_cast<ConstantFPSDNode>(N2.Val);
|
2005-07-10 00:07:11 +00:00
|
|
|
if (N1CFP) {
|
2005-01-07 07:46:32 +00:00
|
|
|
if (N2CFP) {
|
|
|
|
double C1 = N1CFP->getValue(), C2 = N2CFP->getValue();
|
|
|
|
switch (Opcode) {
|
2005-09-28 22:28:18 +00:00
|
|
|
case ISD::FADD: return getConstantFP(C1 + C2, VT);
|
|
|
|
case ISD::FSUB: return getConstantFP(C1 - C2, VT);
|
|
|
|
case ISD::FMUL: return getConstantFP(C1 * C2, VT);
|
|
|
|
case ISD::FDIV:
|
2005-01-07 07:46:32 +00:00
|
|
|
if (C2) return getConstantFP(C1 / C2, VT);
|
|
|
|
break;
|
2005-09-28 22:28:18 +00:00
|
|
|
case ISD::FREM :
|
2005-01-07 07:46:32 +00:00
|
|
|
if (C2) return getConstantFP(fmod(C1, C2), VT);
|
|
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
} else { // Cannonicalize constant to RHS if commutative
|
|
|
|
if (isCommutativeBinOp(Opcode)) {
|
|
|
|
std::swap(N1CFP, N2CFP);
|
|
|
|
std::swap(N1, N2);
|
|
|
|
}
|
|
|
|
}
|
2005-07-10 00:07:11 +00:00
|
|
|
}
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
// Finally, fold operations that do not require constants.
|
|
|
|
switch (Opcode) {
|
2005-07-10 00:07:11 +00:00
|
|
|
case ISD::FP_ROUND_INREG:
|
|
|
|
if (cast<VTSDNode>(N2)->getVT() == VT) return N1; // Not actually rounding.
|
|
|
|
break;
|
|
|
|
case ISD::SIGN_EXTEND_INREG: {
|
|
|
|
MVT::ValueType EVT = cast<VTSDNode>(N2)->getVT();
|
|
|
|
if (EVT == VT) return N1; // Not actually extending
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-04-13 21:23:31 +00:00
|
|
|
// FIXME: figure out how to safely handle things like
|
|
|
|
// int foo(int x) { return 1 << (x & 255); }
|
|
|
|
// int bar() { return foo(256); }
|
|
|
|
#if 0
|
2005-04-12 23:32:28 +00:00
|
|
|
case ISD::SHL:
|
|
|
|
case ISD::SRL:
|
|
|
|
case ISD::SRA:
|
2005-04-13 02:58:13 +00:00
|
|
|
if (N2.getOpcode() == ISD::SIGN_EXTEND_INREG &&
|
2005-07-10 00:07:11 +00:00
|
|
|
cast<VTSDNode>(N2.getOperand(1))->getVT() != MVT::i1)
|
2005-04-12 23:32:28 +00:00
|
|
|
return getNode(Opcode, VT, N1, N2.getOperand(0));
|
2005-04-13 02:58:13 +00:00
|
|
|
else if (N2.getOpcode() == ISD::AND)
|
|
|
|
if (ConstantSDNode *AndRHS = dyn_cast<ConstantSDNode>(N2.getOperand(1))) {
|
|
|
|
// If the and is only masking out bits that cannot effect the shift,
|
|
|
|
// eliminate the and.
|
|
|
|
unsigned NumBits = MVT::getSizeInBits(VT);
|
|
|
|
if ((AndRHS->getValue() & (NumBits-1)) == NumBits-1)
|
|
|
|
return getNode(Opcode, VT, N1, N2.getOperand(0));
|
|
|
|
}
|
2005-04-12 23:32:28 +00:00
|
|
|
break;
|
2005-04-13 21:23:31 +00:00
|
|
|
#endif
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
2005-05-11 18:57:39 +00:00
|
|
|
// Memoize this node if possible.
|
|
|
|
SDNode *N;
|
2006-01-29 07:58:15 +00:00
|
|
|
if (VT != MVT::Flag) {
|
2005-05-11 18:57:39 +00:00
|
|
|
SDNode *&BON = BinaryOps[std::make_pair(Opcode, std::make_pair(N1, N2))];
|
|
|
|
if (BON) return SDOperand(BON, 0);
|
|
|
|
|
|
|
|
BON = N = new SDNode(Opcode, N1, N2);
|
|
|
|
} else {
|
2005-05-12 00:17:04 +00:00
|
|
|
N = new SDNode(Opcode, N1, N2);
|
2005-05-11 18:57:39 +00:00
|
|
|
}
|
|
|
|
|
2005-05-14 07:45:46 +00:00
|
|
|
N->setValueTypes(VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
|
|
|
|
SDOperand N1, SDOperand N2, SDOperand N3) {
|
|
|
|
// Perform various simplifications.
|
|
|
|
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.Val);
|
|
|
|
ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2.Val);
|
|
|
|
ConstantSDNode *N3C = dyn_cast<ConstantSDNode>(N3.Val);
|
|
|
|
switch (Opcode) {
|
2005-08-09 20:20:18 +00:00
|
|
|
case ISD::SETCC: {
|
|
|
|
// Use SimplifySetCC to simplify SETCC's.
|
2005-08-09 23:09:05 +00:00
|
|
|
SDOperand Simp = SimplifySetCC(VT, N1, N2, cast<CondCodeSDNode>(N3)->get());
|
2005-08-09 20:20:18 +00:00
|
|
|
if (Simp.Val) return Simp;
|
|
|
|
break;
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
case ISD::SELECT:
|
|
|
|
if (N1C)
|
|
|
|
if (N1C->getValue())
|
|
|
|
return N2; // select true, X, Y -> X
|
2005-04-21 22:36:52 +00:00
|
|
|
else
|
2005-01-07 07:46:32 +00:00
|
|
|
return N3; // select false, X, Y -> Y
|
|
|
|
|
|
|
|
if (N2 == N3) return N2; // select C, X, X -> X
|
|
|
|
break;
|
2005-01-07 22:49:57 +00:00
|
|
|
case ISD::BRCOND:
|
|
|
|
if (N2C)
|
|
|
|
if (N2C->getValue()) // Unconditional branch
|
|
|
|
return getNode(ISD::BR, MVT::Other, N1, N3);
|
|
|
|
else
|
|
|
|
return N1; // Never-taken branch
|
2005-01-07 23:32:00 +00:00
|
|
|
break;
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
2005-05-14 07:42:29 +00:00
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.reserve(3);
|
|
|
|
Ops.push_back(N1);
|
|
|
|
Ops.push_back(N2);
|
|
|
|
Ops.push_back(N3);
|
|
|
|
|
2005-08-25 19:12:10 +00:00
|
|
|
// Memoize node if it doesn't produce a flag.
|
|
|
|
SDNode *N;
|
|
|
|
if (VT != MVT::Flag) {
|
|
|
|
SDNode *&E = OneResultNodes[std::make_pair(Opcode,std::make_pair(VT, Ops))];
|
|
|
|
if (E) return SDOperand(E, 0);
|
|
|
|
E = N = new SDNode(Opcode, N1, N2, N3);
|
|
|
|
} else {
|
|
|
|
N = new SDNode(Opcode, N1, N2, N3);
|
|
|
|
}
|
2005-05-14 07:29:57 +00:00
|
|
|
N->setValueTypes(VT);
|
2005-01-07 07:46:32 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2005-04-27 20:10:01 +00:00
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
|
2005-07-27 06:12:32 +00:00
|
|
|
SDOperand N1, SDOperand N2, SDOperand N3,
|
2005-04-27 20:10:01 +00:00
|
|
|
SDOperand N4) {
|
2005-05-14 07:32:14 +00:00
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.reserve(4);
|
|
|
|
Ops.push_back(N1);
|
|
|
|
Ops.push_back(N2);
|
|
|
|
Ops.push_back(N3);
|
|
|
|
Ops.push_back(N4);
|
|
|
|
return getNode(Opcode, VT, Ops);
|
2005-04-27 20:10:01 +00:00
|
|
|
}
|
|
|
|
|
2005-07-10 00:29:18 +00:00
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
|
|
|
|
SDOperand N1, SDOperand N2, SDOperand N3,
|
|
|
|
SDOperand N4, SDOperand N5) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.reserve(5);
|
|
|
|
Ops.push_back(N1);
|
|
|
|
Ops.push_back(N2);
|
|
|
|
Ops.push_back(N3);
|
|
|
|
Ops.push_back(N4);
|
|
|
|
Ops.push_back(N5);
|
|
|
|
return getNode(Opcode, VT, Ops);
|
|
|
|
}
|
|
|
|
|
2005-12-10 00:37:58 +00:00
|
|
|
SDOperand SelectionDAG::getLoad(MVT::ValueType VT,
|
|
|
|
SDOperand Chain, SDOperand Ptr,
|
|
|
|
SDOperand SV) {
|
|
|
|
SDNode *&N = Loads[std::make_pair(Ptr, std::make_pair(Chain, VT))];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
N = new SDNode(ISD::LOAD, Chain, Ptr, SV);
|
|
|
|
|
|
|
|
// Loads have a token chain.
|
|
|
|
setNodeValueTypes(N, VT, MVT::Other);
|
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getVecLoad(unsigned Count, MVT::ValueType EVT,
|
|
|
|
SDOperand Chain, SDOperand Ptr,
|
|
|
|
SDOperand SV) {
|
|
|
|
SDNode *&N = Loads[std::make_pair(Ptr, std::make_pair(Chain, EVT))];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.reserve(5);
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Ptr);
|
|
|
|
Ops.push_back(getConstant(Count, MVT::i32));
|
|
|
|
Ops.push_back(getValueType(EVT));
|
|
|
|
Ops.push_back(SV);
|
|
|
|
std::vector<MVT::ValueType> VTs;
|
|
|
|
VTs.reserve(2);
|
|
|
|
VTs.push_back(MVT::Vector); VTs.push_back(MVT::Other); // Add token chain.
|
|
|
|
return getNode(ISD::VLOAD, VTs, Ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::getExtLoad(unsigned Opcode, MVT::ValueType VT,
|
|
|
|
SDOperand Chain, SDOperand Ptr, SDOperand SV,
|
|
|
|
MVT::ValueType EVT) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.reserve(4);
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Ptr);
|
|
|
|
Ops.push_back(SV);
|
|
|
|
Ops.push_back(getValueType(EVT));
|
|
|
|
std::vector<MVT::ValueType> VTs;
|
|
|
|
VTs.reserve(2);
|
|
|
|
VTs.push_back(VT); VTs.push_back(MVT::Other); // Add token chain.
|
|
|
|
return getNode(Opcode, VTs, Ops);
|
|
|
|
}
|
2005-07-10 00:29:18 +00:00
|
|
|
|
2005-05-09 04:14:13 +00:00
|
|
|
SDOperand SelectionDAG::getSrcValue(const Value *V, int Offset) {
|
2005-06-29 18:54:02 +00:00
|
|
|
assert((!V || isa<PointerType>(V->getType())) &&
|
|
|
|
"SrcValue is not a pointer?");
|
2005-05-09 04:14:13 +00:00
|
|
|
SDNode *&N = ValueNodes[std::make_pair(V, Offset)];
|
|
|
|
if (N) return SDOperand(N, 0);
|
|
|
|
|
|
|
|
N = new SrcValueSDNode(V, Offset);
|
2005-04-27 20:10:01 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2006-01-25 18:21:52 +00:00
|
|
|
SDOperand SelectionDAG::getVAArg(MVT::ValueType VT,
|
|
|
|
SDOperand Chain, SDOperand Ptr,
|
|
|
|
SDOperand SV) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.reserve(3);
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Ptr);
|
|
|
|
Ops.push_back(SV);
|
|
|
|
std::vector<MVT::ValueType> VTs;
|
|
|
|
VTs.reserve(2);
|
|
|
|
VTs.push_back(VT); VTs.push_back(MVT::Other); // Add token chain.
|
|
|
|
return getNode(ISD::VAARG, VTs, Ops);
|
|
|
|
}
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
|
2005-05-14 06:20:26 +00:00
|
|
|
std::vector<SDOperand> &Ops) {
|
|
|
|
switch (Ops.size()) {
|
2005-01-07 07:46:32 +00:00
|
|
|
case 0: return getNode(Opcode, VT);
|
2005-05-14 06:20:26 +00:00
|
|
|
case 1: return getNode(Opcode, VT, Ops[0]);
|
|
|
|
case 2: return getNode(Opcode, VT, Ops[0], Ops[1]);
|
|
|
|
case 3: return getNode(Opcode, VT, Ops[0], Ops[1], Ops[2]);
|
2005-04-09 03:27:28 +00:00
|
|
|
default: break;
|
|
|
|
}
|
2005-11-09 23:47:37 +00:00
|
|
|
|
2005-05-14 06:20:26 +00:00
|
|
|
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(Ops[1].Val);
|
2005-04-09 03:27:28 +00:00
|
|
|
switch (Opcode) {
|
|
|
|
default: break;
|
|
|
|
case ISD::BRCONDTWOWAY:
|
|
|
|
if (N1C)
|
|
|
|
if (N1C->getValue()) // Unconditional branch to true dest.
|
2005-05-14 06:20:26 +00:00
|
|
|
return getNode(ISD::BR, MVT::Other, Ops[0], Ops[2]);
|
2005-04-09 03:27:28 +00:00
|
|
|
else // Unconditional branch to false dest.
|
2005-05-14 06:20:26 +00:00
|
|
|
return getNode(ISD::BR, MVT::Other, Ops[0], Ops[3]);
|
2005-04-09 03:27:28 +00:00
|
|
|
break;
|
2005-08-16 19:49:35 +00:00
|
|
|
case ISD::BRTWOWAY_CC:
|
|
|
|
assert(Ops.size() == 6 && "BRTWOWAY_CC takes 6 operands!");
|
|
|
|
assert(Ops[2].getValueType() == Ops[3].getValueType() &&
|
|
|
|
"LHS and RHS of comparison must have same type!");
|
|
|
|
break;
|
2005-07-10 00:29:18 +00:00
|
|
|
case ISD::TRUNCSTORE: {
|
|
|
|
assert(Ops.size() == 5 && "TRUNCSTORE takes 5 operands!");
|
|
|
|
MVT::ValueType EVT = cast<VTSDNode>(Ops[4])->getVT();
|
|
|
|
#if 0 // FIXME: If the target supports EVT natively, convert to a truncate/store
|
|
|
|
// If this is a truncating store of a constant, convert to the desired type
|
|
|
|
// and store it instead.
|
|
|
|
if (isa<Constant>(Ops[0])) {
|
|
|
|
SDOperand Op = getNode(ISD::TRUNCATE, EVT, N1);
|
|
|
|
if (isa<Constant>(Op))
|
|
|
|
N1 = Op;
|
|
|
|
}
|
|
|
|
// Also for ConstantFP?
|
|
|
|
#endif
|
|
|
|
if (Ops[0].getValueType() == EVT) // Normal store?
|
|
|
|
return getNode(ISD::STORE, VT, Ops[0], Ops[1], Ops[2], Ops[3]);
|
|
|
|
assert(Ops[1].getValueType() > EVT && "Not a truncation?");
|
|
|
|
assert(MVT::isInteger(Ops[1].getValueType()) == MVT::isInteger(EVT) &&
|
|
|
|
"Can't do FP-INT conversion!");
|
|
|
|
break;
|
|
|
|
}
|
2005-08-24 22:44:39 +00:00
|
|
|
case ISD::SELECT_CC: {
|
2005-10-05 06:37:22 +00:00
|
|
|
assert(Ops.size() == 5 && "SELECT_CC takes 5 operands!");
|
2005-08-24 22:44:39 +00:00
|
|
|
assert(Ops[0].getValueType() == Ops[1].getValueType() &&
|
|
|
|
"LHS and RHS of condition must have same type!");
|
|
|
|
assert(Ops[2].getValueType() == Ops[3].getValueType() &&
|
|
|
|
"True and False arms of SelectCC must have same type!");
|
|
|
|
assert(Ops[2].getValueType() == VT &&
|
|
|
|
"select_cc node must be of same type as true and false value!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ISD::BR_CC: {
|
2005-10-05 06:37:22 +00:00
|
|
|
assert(Ops.size() == 5 && "BR_CC takes 5 operands!");
|
2005-08-24 22:44:39 +00:00
|
|
|
assert(Ops[2].getValueType() == Ops[3].getValueType() &&
|
|
|
|
"LHS/RHS of comparison should match types!");
|
|
|
|
break;
|
|
|
|
}
|
2005-04-09 03:27:28 +00:00
|
|
|
}
|
|
|
|
|
2005-05-14 07:42:29 +00:00
|
|
|
// Memoize nodes.
|
2005-08-25 19:12:10 +00:00
|
|
|
SDNode *N;
|
|
|
|
if (VT != MVT::Flag) {
|
|
|
|
SDNode *&E =
|
|
|
|
OneResultNodes[std::make_pair(Opcode, std::make_pair(VT, Ops))];
|
|
|
|
if (E) return SDOperand(E, 0);
|
|
|
|
E = N = new SDNode(Opcode, Ops);
|
|
|
|
} else {
|
|
|
|
N = new SDNode(Opcode, Ops);
|
|
|
|
}
|
2005-05-14 07:25:05 +00:00
|
|
|
N->setValueTypes(VT);
|
2005-04-09 03:27:28 +00:00
|
|
|
AllNodes.push_back(N);
|
|
|
|
return SDOperand(N, 0);
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
|
2005-05-14 06:20:26 +00:00
|
|
|
SDOperand SelectionDAG::getNode(unsigned Opcode,
|
|
|
|
std::vector<MVT::ValueType> &ResultTys,
|
|
|
|
std::vector<SDOperand> &Ops) {
|
|
|
|
if (ResultTys.size() == 1)
|
|
|
|
return getNode(Opcode, ResultTys[0], Ops);
|
|
|
|
|
2005-07-10 01:55:33 +00:00
|
|
|
switch (Opcode) {
|
|
|
|
case ISD::EXTLOAD:
|
|
|
|
case ISD::SEXTLOAD:
|
|
|
|
case ISD::ZEXTLOAD: {
|
|
|
|
MVT::ValueType EVT = cast<VTSDNode>(Ops[3])->getVT();
|
|
|
|
assert(Ops.size() == 4 && ResultTys.size() == 2 && "Bad *EXTLOAD!");
|
|
|
|
// If they are asking for an extending load from/to the same thing, return a
|
|
|
|
// normal load.
|
|
|
|
if (ResultTys[0] == EVT)
|
|
|
|
return getLoad(ResultTys[0], Ops[0], Ops[1], Ops[2]);
|
|
|
|
assert(EVT < ResultTys[0] &&
|
|
|
|
"Should only be an extending load, not truncating!");
|
|
|
|
assert((Opcode == ISD::EXTLOAD || MVT::isInteger(ResultTys[0])) &&
|
|
|
|
"Cannot sign/zero extend a FP load!");
|
|
|
|
assert(MVT::isInteger(ResultTys[0]) == MVT::isInteger(EVT) &&
|
|
|
|
"Cannot convert from FP to Int or Int -> FP!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-05-14 07:25:05 +00:00
|
|
|
// FIXME: figure out how to safely handle things like
|
|
|
|
// int foo(int x) { return 1 << (x & 255); }
|
|
|
|
// int bar() { return foo(256); }
|
|
|
|
#if 0
|
|
|
|
case ISD::SRA_PARTS:
|
|
|
|
case ISD::SRL_PARTS:
|
|
|
|
case ISD::SHL_PARTS:
|
|
|
|
if (N3.getOpcode() == ISD::SIGN_EXTEND_INREG &&
|
2005-07-10 00:07:11 +00:00
|
|
|
cast<VTSDNode>(N3.getOperand(1))->getVT() != MVT::i1)
|
2005-05-14 07:25:05 +00:00
|
|
|
return getNode(Opcode, VT, N1, N2, N3.getOperand(0));
|
|
|
|
else if (N3.getOpcode() == ISD::AND)
|
|
|
|
if (ConstantSDNode *AndRHS = dyn_cast<ConstantSDNode>(N3.getOperand(1))) {
|
|
|
|
// If the and is only masking out bits that cannot effect the shift,
|
|
|
|
// eliminate the and.
|
|
|
|
unsigned NumBits = MVT::getSizeInBits(VT)*2;
|
|
|
|
if ((AndRHS->getValue() & (NumBits-1)) == NumBits-1)
|
|
|
|
return getNode(Opcode, VT, N1, N2, N3.getOperand(0));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
2005-07-10 01:55:33 +00:00
|
|
|
}
|
2005-05-14 06:20:26 +00:00
|
|
|
|
2005-08-25 19:12:10 +00:00
|
|
|
// Memoize the node unless it returns a flag.
|
|
|
|
SDNode *N;
|
|
|
|
if (ResultTys.back() != MVT::Flag) {
|
|
|
|
SDNode *&E =
|
|
|
|
ArbitraryNodes[std::make_pair(Opcode, std::make_pair(ResultTys, Ops))];
|
|
|
|
if (E) return SDOperand(E, 0);
|
|
|
|
E = N = new SDNode(Opcode, Ops);
|
|
|
|
} else {
|
|
|
|
N = new SDNode(Opcode, Ops);
|
|
|
|
}
|
2005-11-08 23:30:28 +00:00
|
|
|
setNodeValueTypes(N, ResultTys);
|
2005-05-14 06:42:57 +00:00
|
|
|
AllNodes.push_back(N);
|
2005-05-14 06:20:26 +00:00
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
|
|
|
|
2005-11-08 23:30:28 +00:00
|
|
|
void SelectionDAG::setNodeValueTypes(SDNode *N,
|
|
|
|
std::vector<MVT::ValueType> &RetVals) {
|
|
|
|
switch (RetVals.size()) {
|
|
|
|
case 0: return;
|
|
|
|
case 1: N->setValueTypes(RetVals[0]); return;
|
|
|
|
case 2: setNodeValueTypes(N, RetVals[0], RetVals[1]); return;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::list<std::vector<MVT::ValueType> >::iterator I =
|
|
|
|
std::find(VTList.begin(), VTList.end(), RetVals);
|
|
|
|
if (I == VTList.end()) {
|
|
|
|
VTList.push_front(RetVals);
|
|
|
|
I = VTList.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
N->setValueTypes(&(*I)[0], I->size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SelectionDAG::setNodeValueTypes(SDNode *N, MVT::ValueType VT1,
|
|
|
|
MVT::ValueType VT2) {
|
|
|
|
for (std::list<std::vector<MVT::ValueType> >::iterator I = VTList.begin(),
|
|
|
|
E = VTList.end(); I != E; ++I) {
|
|
|
|
if (I->size() == 2 && (*I)[0] == VT1 && (*I)[1] == VT2) {
|
|
|
|
N->setValueTypes(&(*I)[0], 2);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::vector<MVT::ValueType> V;
|
|
|
|
V.push_back(VT1);
|
|
|
|
V.push_back(VT2);
|
|
|
|
VTList.push_front(V);
|
|
|
|
N->setValueTypes(&(*VTList.begin())[0], 2);
|
|
|
|
}
|
|
|
|
|
2006-01-28 09:32:45 +00:00
|
|
|
/// UpdateNodeOperands - *Mutate* the specified node in-place to have the
|
|
|
|
/// specified operands. If the resultant node already exists in the DAG,
|
|
|
|
/// this does not modify the specified node, instead it returns the node that
|
|
|
|
/// already exists. If the resultant node does not exist in the DAG, the
|
|
|
|
/// input node is returned. As a degenerate case, if you specify the same
|
|
|
|
/// input operands as the node already has, the input node is returned.
|
|
|
|
SDOperand SelectionDAG::
|
|
|
|
UpdateNodeOperands(SDOperand InN, SDOperand Op) {
|
|
|
|
SDNode *N = InN.Val;
|
|
|
|
assert(N->getNumOperands() == 1 && "Update with wrong number of operands");
|
|
|
|
|
|
|
|
// Check to see if there is no change.
|
|
|
|
if (Op == N->getOperand(0)) return InN;
|
|
|
|
|
|
|
|
// See if the modified node already exists.
|
|
|
|
SDNode **NewSlot = FindModifiedNodeSlot(N, Op);
|
|
|
|
if (NewSlot && *NewSlot)
|
|
|
|
return SDOperand(*NewSlot, InN.ResNo);
|
|
|
|
|
|
|
|
// Nope it doesn't. Remove the node from it's current place in the maps.
|
|
|
|
if (NewSlot)
|
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
|
|
|
|
// Now we update the operands.
|
|
|
|
N->OperandList[0].Val->removeUser(N);
|
|
|
|
Op.Val->addUser(N);
|
|
|
|
N->OperandList[0] = Op;
|
|
|
|
|
|
|
|
// If this gets put into a CSE map, add it.
|
|
|
|
if (NewSlot) *NewSlot = N;
|
|
|
|
return InN;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::
|
|
|
|
UpdateNodeOperands(SDOperand InN, SDOperand Op1, SDOperand Op2) {
|
|
|
|
SDNode *N = InN.Val;
|
|
|
|
assert(N->getNumOperands() == 2 && "Update with wrong number of operands");
|
|
|
|
|
|
|
|
// Check to see if there is no change.
|
|
|
|
bool AnyChange = false;
|
|
|
|
if (Op1 == N->getOperand(0) && Op2 == N->getOperand(1))
|
|
|
|
return InN; // No operands changed, just return the input node.
|
|
|
|
|
|
|
|
// See if the modified node already exists.
|
|
|
|
SDNode **NewSlot = FindModifiedNodeSlot(N, Op1, Op2);
|
|
|
|
if (NewSlot && *NewSlot)
|
|
|
|
return SDOperand(*NewSlot, InN.ResNo);
|
|
|
|
|
|
|
|
// Nope it doesn't. Remove the node from it's current place in the maps.
|
|
|
|
if (NewSlot)
|
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
|
|
|
|
// Now we update the operands.
|
|
|
|
if (N->OperandList[0] != Op1) {
|
|
|
|
N->OperandList[0].Val->removeUser(N);
|
|
|
|
Op1.Val->addUser(N);
|
|
|
|
N->OperandList[0] = Op1;
|
|
|
|
}
|
|
|
|
if (N->OperandList[1] != Op2) {
|
|
|
|
N->OperandList[1].Val->removeUser(N);
|
|
|
|
Op2.Val->addUser(N);
|
|
|
|
N->OperandList[1] = Op2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this gets put into a CSE map, add it.
|
|
|
|
if (NewSlot) *NewSlot = N;
|
|
|
|
return InN;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::
|
|
|
|
UpdateNodeOperands(SDOperand N, SDOperand Op1, SDOperand Op2, SDOperand Op3) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op1);
|
|
|
|
Ops.push_back(Op2);
|
|
|
|
Ops.push_back(Op3);
|
|
|
|
return UpdateNodeOperands(N, Ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDOperand SelectionDAG::
|
|
|
|
UpdateNodeOperands(SDOperand N, SDOperand Op1, SDOperand Op2,
|
|
|
|
SDOperand Op3, SDOperand Op4) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op1);
|
|
|
|
Ops.push_back(Op2);
|
|
|
|
Ops.push_back(Op3);
|
|
|
|
Ops.push_back(Op4);
|
|
|
|
return UpdateNodeOperands(N, Ops);
|
|
|
|
}
|
|
|
|
|
2006-01-28 10:09:25 +00:00
|
|
|
SDOperand SelectionDAG::
|
|
|
|
UpdateNodeOperands(SDOperand N, SDOperand Op1, SDOperand Op2,
|
|
|
|
SDOperand Op3, SDOperand Op4, SDOperand Op5) {
|
|
|
|
std::vector<SDOperand> Ops;
|
|
|
|
Ops.push_back(Op1);
|
|
|
|
Ops.push_back(Op2);
|
|
|
|
Ops.push_back(Op3);
|
|
|
|
Ops.push_back(Op4);
|
|
|
|
Ops.push_back(Op5);
|
|
|
|
return UpdateNodeOperands(N, Ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-28 09:32:45 +00:00
|
|
|
SDOperand SelectionDAG::
|
|
|
|
UpdateNodeOperands(SDOperand InN, const std::vector<SDOperand> &Ops) {
|
|
|
|
SDNode *N = InN.Val;
|
|
|
|
assert(N->getNumOperands() == Ops.size() &&
|
|
|
|
"Update with wrong number of operands");
|
|
|
|
|
|
|
|
// Check to see if there is no change.
|
|
|
|
unsigned NumOps = Ops.size();
|
|
|
|
bool AnyChange = false;
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
if (Ops[i] != N->getOperand(i)) {
|
|
|
|
AnyChange = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No operands changed, just return the input node.
|
|
|
|
if (!AnyChange) return InN;
|
|
|
|
|
|
|
|
// See if the modified node already exists.
|
|
|
|
SDNode **NewSlot = FindModifiedNodeSlot(N, Ops);
|
|
|
|
if (NewSlot && *NewSlot)
|
|
|
|
return SDOperand(*NewSlot, InN.ResNo);
|
|
|
|
|
|
|
|
// Nope it doesn't. Remove the node from it's current place in the maps.
|
|
|
|
if (NewSlot)
|
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
|
|
|
|
// Now we update the operands.
|
|
|
|
for (unsigned i = 0; i != NumOps; ++i) {
|
|
|
|
if (N->OperandList[i] != Ops[i]) {
|
|
|
|
N->OperandList[i].Val->removeUser(N);
|
|
|
|
Ops[i].Val->addUser(N);
|
|
|
|
N->OperandList[i] = Ops[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this gets put into a CSE map, add it.
|
|
|
|
if (NewSlot) *NewSlot = N;
|
|
|
|
return InN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-08-16 18:17:10 +00:00
|
|
|
|
|
|
|
/// SelectNodeTo - These are used for target selectors to *mutate* the
|
|
|
|
/// specified node to have the specified return type, Target opcode, and
|
|
|
|
/// operands. Note that target opcodes are stored as
|
|
|
|
/// ISD::BUILTIN_OP_END+TargetOpcode in the node opcode field.
|
2005-12-01 18:00:57 +00:00
|
|
|
///
|
|
|
|
/// Note that SelectNodeTo returns the resultant node. If there is already a
|
|
|
|
/// node of the specified opcode and operands, it returns that node instead of
|
|
|
|
/// the current one.
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
SDNode *&ON = NullaryOps[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc, VT)];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-24 23:00:29 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
2005-08-24 23:00:29 +00:00
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-24 23:00:29 +00:00
|
|
|
}
|
2005-11-19 01:44:53 +00:00
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
SDNode *&ON = UnaryOps[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(Op1, VT))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-16 18:17:10 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
|
|
|
N->setOperands(Op1);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-16 18:17:10 +00:00
|
|
|
}
|
2005-11-19 01:44:53 +00:00
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1,
|
|
|
|
SDOperand Op2) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
SDNode *&ON = BinaryOps[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(Op1, Op2))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-16 18:17:10 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
|
|
|
N->setOperands(Op1, Op2);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-16 18:17:10 +00:00
|
|
|
}
|
2005-11-19 01:44:53 +00:00
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1,
|
|
|
|
SDOperand Op2, SDOperand Op3) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
SDNode *&ON = OneResultNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VT, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-21 19:48:59 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
2005-11-19 01:44:53 +00:00
|
|
|
N->setValueTypes(VT);
|
|
|
|
N->setOperands(Op1, Op2, Op3);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-21 19:48:59 +00:00
|
|
|
}
|
2005-11-19 01:44:53 +00:00
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1,
|
|
|
|
SDOperand Op2, SDOperand Op3,
|
|
|
|
SDOperand Op4) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
OpList.push_back(Op4);
|
|
|
|
SDNode *&ON = OneResultNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VT, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-16 18:17:10 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
2005-11-19 01:44:53 +00:00
|
|
|
N->setOperands(Op1, Op2, Op3, Op4);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-11-19 01:44:53 +00:00
|
|
|
}
|
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1,
|
|
|
|
SDOperand Op2, SDOperand Op3,SDOperand Op4,
|
|
|
|
SDOperand Op5) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
OpList.push_back(Op4); OpList.push_back(Op5);
|
|
|
|
SDNode *&ON = OneResultNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VT, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-11-19 01:44:53 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
|
|
|
N->setOperands(Op1, Op2, Op3, Op4, Op5);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-16 18:17:10 +00:00
|
|
|
}
|
2005-11-19 01:44:53 +00:00
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1,
|
|
|
|
SDOperand Op2, SDOperand Op3,SDOperand Op4,
|
|
|
|
SDOperand Op5, SDOperand Op6) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
OpList.push_back(Op4); OpList.push_back(Op5); OpList.push_back(Op6);
|
|
|
|
SDNode *&ON = OneResultNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VT, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-11-30 02:04:11 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
|
|
|
N->setOperands(Op1, Op2, Op3, Op4, Op5, Op6);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-11-30 02:04:11 +00:00
|
|
|
}
|
|
|
|
|
2006-01-23 20:59:12 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1,
|
|
|
|
SDOperand Op2, SDOperand Op3,SDOperand Op4,
|
|
|
|
SDOperand Op5, SDOperand Op6,
|
|
|
|
SDOperand Op7) {
|
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
OpList.push_back(Op4); OpList.push_back(Op5); OpList.push_back(Op6);
|
|
|
|
OpList.push_back(Op7);
|
|
|
|
SDNode *&ON = OneResultNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VT, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
|
|
|
N->setOperands(Op1, Op2, Op3, Op4, Op5, Op6, Op7);
|
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
2006-01-23 21:51:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT, SDOperand Op1,
|
|
|
|
SDOperand Op2, SDOperand Op3,SDOperand Op4,
|
|
|
|
SDOperand Op5, SDOperand Op6,
|
|
|
|
SDOperand Op7, SDOperand Op8) {
|
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
OpList.push_back(Op4); OpList.push_back(Op5); OpList.push_back(Op6);
|
|
|
|
OpList.push_back(Op7); OpList.push_back(Op8);
|
|
|
|
SDNode *&ON = OneResultNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VT, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
N->setValueTypes(VT);
|
|
|
|
N->setOperands(Op1, Op2, Op3, Op4, Op5, Op6, Op7, Op8);
|
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
|
|
|
return SDOperand(N, 0);
|
|
|
|
}
|
2006-01-23 20:59:12 +00:00
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT1, MVT::ValueType VT2,
|
|
|
|
SDOperand Op1, SDOperand Op2) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2);
|
|
|
|
std::vector<MVT::ValueType> VTList;
|
|
|
|
VTList.push_back(VT1); VTList.push_back(VT2);
|
|
|
|
SDNode *&ON = ArbitraryNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VTList, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-11-19 01:44:53 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
|
|
|
setNodeValueTypes(N, VT1, VT2);
|
|
|
|
N->setOperands(Op1, Op2);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-11-19 01:44:53 +00:00
|
|
|
}
|
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT1, MVT::ValueType VT2,
|
|
|
|
SDOperand Op1, SDOperand Op2,
|
|
|
|
SDOperand Op3) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
std::vector<MVT::ValueType> VTList;
|
|
|
|
VTList.push_back(VT1); VTList.push_back(VT2);
|
|
|
|
SDNode *&ON = ArbitraryNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VTList, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-21 22:30:30 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
2005-11-08 23:30:28 +00:00
|
|
|
setNodeValueTypes(N, VT1, VT2);
|
2005-08-21 22:30:30 +00:00
|
|
|
N->setOperands(Op1, Op2, Op3);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-21 22:30:30 +00:00
|
|
|
}
|
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT1, MVT::ValueType VT2,
|
|
|
|
SDOperand Op1, SDOperand Op2,
|
|
|
|
SDOperand Op3, SDOperand Op4) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
OpList.push_back(Op4);
|
|
|
|
std::vector<MVT::ValueType> VTList;
|
|
|
|
VTList.push_back(VT1); VTList.push_back(VT2);
|
|
|
|
SDNode *&ON = ArbitraryNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VTList, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-18 07:30:15 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
2005-11-19 01:44:53 +00:00
|
|
|
setNodeValueTypes(N, VT1, VT2);
|
2005-08-18 07:30:15 +00:00
|
|
|
N->setOperands(Op1, Op2, Op3, Op4);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-18 07:30:15 +00:00
|
|
|
}
|
2005-11-19 01:44:53 +00:00
|
|
|
|
2005-11-30 22:45:14 +00:00
|
|
|
SDOperand SelectionDAG::SelectNodeTo(SDNode *N, unsigned TargetOpc,
|
|
|
|
MVT::ValueType VT1, MVT::ValueType VT2,
|
|
|
|
SDOperand Op1, SDOperand Op2,
|
|
|
|
SDOperand Op3, SDOperand Op4,
|
|
|
|
SDOperand Op5) {
|
2005-12-01 18:00:57 +00:00
|
|
|
// If an identical node already exists, use it.
|
|
|
|
std::vector<SDOperand> OpList;
|
|
|
|
OpList.push_back(Op1); OpList.push_back(Op2); OpList.push_back(Op3);
|
|
|
|
OpList.push_back(Op4); OpList.push_back(Op5);
|
|
|
|
std::vector<MVT::ValueType> VTList;
|
|
|
|
VTList.push_back(VT1); VTList.push_back(VT2);
|
|
|
|
SDNode *&ON = ArbitraryNodes[std::make_pair(ISD::BUILTIN_OP_END+TargetOpc,
|
|
|
|
std::make_pair(VTList, OpList))];
|
|
|
|
if (ON) return SDOperand(ON, 0);
|
|
|
|
|
2005-08-21 18:49:33 +00:00
|
|
|
RemoveNodeFromCSEMaps(N);
|
|
|
|
N->MorphNodeTo(ISD::BUILTIN_OP_END+TargetOpc);
|
2005-11-19 01:44:53 +00:00
|
|
|
setNodeValueTypes(N, VT1, VT2);
|
2005-08-21 18:49:33 +00:00
|
|
|
N->setOperands(Op1, Op2, Op3, Op4, Op5);
|
2005-12-01 18:00:57 +00:00
|
|
|
|
|
|
|
ON = N; // Memoize the new node.
|
2005-11-30 22:45:14 +00:00
|
|
|
return SDOperand(N, 0);
|
2005-08-21 18:49:33 +00:00
|
|
|
}
|
2005-08-16 18:17:10 +00:00
|
|
|
|
2005-11-19 01:44:53 +00:00
|
|
|
// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead.
|
2005-08-17 19:00:20 +00:00
|
|
|
/// This can cause recursive merging of nodes in the DAG.
|
|
|
|
///
|
2005-08-26 18:36:28 +00:00
|
|
|
/// This version assumes From/To have a single result value.
|
|
|
|
///
|
2005-09-07 05:37:01 +00:00
|
|
|
void SelectionDAG::ReplaceAllUsesWith(SDOperand FromN, SDOperand ToN,
|
|
|
|
std::vector<SDNode*> *Deleted) {
|
2005-08-26 18:36:28 +00:00
|
|
|
SDNode *From = FromN.Val, *To = ToN.Val;
|
|
|
|
assert(From->getNumValues() == 1 && To->getNumValues() == 1 &&
|
|
|
|
"Cannot replace with this method!");
|
|
|
|
assert(From != To && "Cannot replace uses of with self");
|
|
|
|
|
|
|
|
while (!From->use_empty()) {
|
|
|
|
// Process users until they are all gone.
|
|
|
|
SDNode *U = *From->use_begin();
|
|
|
|
|
|
|
|
// This node is about to morph, remove its old self from the CSE maps.
|
|
|
|
RemoveNodeFromCSEMaps(U);
|
|
|
|
|
2005-11-08 22:07:03 +00:00
|
|
|
for (SDOperand *I = U->OperandList, *E = U->OperandList+U->NumOperands;
|
|
|
|
I != E; ++I)
|
|
|
|
if (I->Val == From) {
|
2005-08-26 18:36:28 +00:00
|
|
|
From->removeUser(U);
|
2005-11-08 22:07:03 +00:00
|
|
|
I->Val = To;
|
2005-08-26 18:36:28 +00:00
|
|
|
To->addUser(U);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we have modified U, add it back to the CSE maps. If it already
|
|
|
|
// exists there, recursively merge the results together.
|
2005-09-07 05:37:01 +00:00
|
|
|
if (SDNode *Existing = AddNonLeafNodeToCSEMaps(U)) {
|
|
|
|
ReplaceAllUsesWith(U, Existing, Deleted);
|
2005-08-26 18:36:28 +00:00
|
|
|
// U is now dead.
|
2005-09-07 05:37:01 +00:00
|
|
|
if (Deleted) Deleted->push_back(U);
|
|
|
|
DeleteNodeNotInCSEMaps(U);
|
|
|
|
}
|
2005-08-26 18:36:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead.
|
|
|
|
/// This can cause recursive merging of nodes in the DAG.
|
|
|
|
///
|
|
|
|
/// This version assumes From/To have matching types and numbers of result
|
|
|
|
/// values.
|
|
|
|
///
|
2005-09-07 05:37:01 +00:00
|
|
|
void SelectionDAG::ReplaceAllUsesWith(SDNode *From, SDNode *To,
|
|
|
|
std::vector<SDNode*> *Deleted) {
|
2005-08-17 19:00:20 +00:00
|
|
|
assert(From != To && "Cannot replace uses of with self");
|
2005-08-26 18:36:28 +00:00
|
|
|
assert(From->getNumValues() == To->getNumValues() &&
|
|
|
|
"Cannot use this version of ReplaceAllUsesWith!");
|
|
|
|
if (From->getNumValues() == 1) { // If possible, use the faster version.
|
2005-09-07 05:37:01 +00:00
|
|
|
ReplaceAllUsesWith(SDOperand(From, 0), SDOperand(To, 0), Deleted);
|
2005-08-26 18:36:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-08-17 19:00:20 +00:00
|
|
|
while (!From->use_empty()) {
|
|
|
|
// Process users until they are all gone.
|
|
|
|
SDNode *U = *From->use_begin();
|
|
|
|
|
|
|
|
// This node is about to morph, remove its old self from the CSE maps.
|
|
|
|
RemoveNodeFromCSEMaps(U);
|
|
|
|
|
2005-11-08 22:07:03 +00:00
|
|
|
for (SDOperand *I = U->OperandList, *E = U->OperandList+U->NumOperands;
|
|
|
|
I != E; ++I)
|
|
|
|
if (I->Val == From) {
|
2005-08-17 19:00:20 +00:00
|
|
|
From->removeUser(U);
|
2005-11-08 22:07:03 +00:00
|
|
|
I->Val = To;
|
2005-08-17 19:00:20 +00:00
|
|
|
To->addUser(U);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we have modified U, add it back to the CSE maps. If it already
|
|
|
|
// exists there, recursively merge the results together.
|
2005-09-07 05:37:01 +00:00
|
|
|
if (SDNode *Existing = AddNonLeafNodeToCSEMaps(U)) {
|
|
|
|
ReplaceAllUsesWith(U, Existing, Deleted);
|
|
|
|
// U is now dead.
|
|
|
|
if (Deleted) Deleted->push_back(U);
|
|
|
|
DeleteNodeNotInCSEMaps(U);
|
|
|
|
}
|
2005-08-17 19:00:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-26 18:36:28 +00:00
|
|
|
/// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead.
|
|
|
|
/// This can cause recursive merging of nodes in the DAG.
|
|
|
|
///
|
|
|
|
/// This version can replace From with any result values. To must match the
|
|
|
|
/// number and types of values returned by From.
|
2005-08-24 22:44:39 +00:00
|
|
|
void SelectionDAG::ReplaceAllUsesWith(SDNode *From,
|
2005-09-07 05:37:01 +00:00
|
|
|
const std::vector<SDOperand> &To,
|
|
|
|
std::vector<SDNode*> *Deleted) {
|
2005-08-24 22:44:39 +00:00
|
|
|
assert(From->getNumValues() == To.size() &&
|
|
|
|
"Incorrect number of values to replace with!");
|
2005-08-28 23:59:36 +00:00
|
|
|
if (To.size() == 1 && To[0].Val->getNumValues() == 1) {
|
2005-08-24 22:44:39 +00:00
|
|
|
// Degenerate case handled above.
|
2005-09-07 05:37:01 +00:00
|
|
|
ReplaceAllUsesWith(SDOperand(From, 0), To[0], Deleted);
|
2005-08-24 22:44:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!From->use_empty()) {
|
|
|
|
// Process users until they are all gone.
|
|
|
|
SDNode *U = *From->use_begin();
|
|
|
|
|
|
|
|
// This node is about to morph, remove its old self from the CSE maps.
|
|
|
|
RemoveNodeFromCSEMaps(U);
|
|
|
|
|
2005-11-08 22:07:03 +00:00
|
|
|
for (SDOperand *I = U->OperandList, *E = U->OperandList+U->NumOperands;
|
|
|
|
I != E; ++I)
|
|
|
|
if (I->Val == From) {
|
|
|
|
const SDOperand &ToOp = To[I->ResNo];
|
2005-08-24 22:44:39 +00:00
|
|
|
From->removeUser(U);
|
2005-11-08 22:07:03 +00:00
|
|
|
*I = ToOp;
|
2005-08-24 22:44:39 +00:00
|
|
|
ToOp.Val->addUser(U);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we have modified U, add it back to the CSE maps. If it already
|
|
|
|
// exists there, recursively merge the results together.
|
2005-09-07 05:37:01 +00:00
|
|
|
if (SDNode *Existing = AddNonLeafNodeToCSEMaps(U)) {
|
|
|
|
ReplaceAllUsesWith(U, Existing, Deleted);
|
|
|
|
// U is now dead.
|
|
|
|
if (Deleted) Deleted->push_back(U);
|
|
|
|
DeleteNodeNotInCSEMaps(U);
|
|
|
|
}
|
2005-08-24 22:44:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-17 20:08:02 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// SDNode Class
|
|
|
|
//===----------------------------------------------------------------------===//
|
2005-08-16 18:17:10 +00:00
|
|
|
|
2005-11-08 23:30:28 +00:00
|
|
|
|
|
|
|
/// getValueTypeList - Return a pointer to the specified value type.
|
|
|
|
///
|
|
|
|
MVT::ValueType *SDNode::getValueTypeList(MVT::ValueType VT) {
|
|
|
|
static MVT::ValueType VTs[MVT::LAST_VALUETYPE];
|
|
|
|
VTs[VT] = VT;
|
|
|
|
return &VTs[VT];
|
|
|
|
}
|
|
|
|
|
2005-01-12 18:37:47 +00:00
|
|
|
/// hasNUsesOfValue - Return true if there are exactly NUSES uses of the
|
|
|
|
/// indicated value. This method ignores uses of other values defined by this
|
|
|
|
/// operation.
|
|
|
|
bool SDNode::hasNUsesOfValue(unsigned NUses, unsigned Value) {
|
|
|
|
assert(Value < getNumValues() && "Bad value!");
|
|
|
|
|
|
|
|
// If there is only one value, this is easy.
|
|
|
|
if (getNumValues() == 1)
|
|
|
|
return use_size() == NUses;
|
|
|
|
if (Uses.size() < NUses) return false;
|
|
|
|
|
|
|
|
SDOperand TheValue(this, Value);
|
|
|
|
|
|
|
|
std::set<SDNode*> UsersHandled;
|
|
|
|
|
|
|
|
for (std::vector<SDNode*>::iterator UI = Uses.begin(), E = Uses.end();
|
|
|
|
UI != E; ++UI) {
|
|
|
|
SDNode *User = *UI;
|
|
|
|
if (User->getNumOperands() == 1 ||
|
|
|
|
UsersHandled.insert(User).second) // First time we've seen this?
|
|
|
|
for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i)
|
|
|
|
if (User->getOperand(i) == TheValue) {
|
|
|
|
if (NUses == 0)
|
|
|
|
return false; // too many uses
|
|
|
|
--NUses;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Found exactly the right number of uses?
|
|
|
|
return NUses == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-16 18:33:07 +00:00
|
|
|
const char *SDNode::getOperationName(const SelectionDAG *G) const {
|
2005-01-10 23:25:25 +00:00
|
|
|
switch (getOpcode()) {
|
2005-08-16 18:33:07 +00:00
|
|
|
default:
|
|
|
|
if (getOpcode() < ISD::BUILTIN_OP_END)
|
|
|
|
return "<<Unknown DAG Node>>";
|
|
|
|
else {
|
2005-12-20 06:22:03 +00:00
|
|
|
if (G) {
|
2005-08-16 18:33:07 +00:00
|
|
|
if (const TargetInstrInfo *TII = G->getTarget().getInstrInfo())
|
2005-09-09 22:35:03 +00:00
|
|
|
if (getOpcode()-ISD::BUILTIN_OP_END < TII->getNumOpcodes())
|
|
|
|
return TII->getName(getOpcode()-ISD::BUILTIN_OP_END);
|
2005-12-19 23:11:49 +00:00
|
|
|
|
2005-12-20 06:22:03 +00:00
|
|
|
TargetLowering &TLI = G->getTargetLoweringInfo();
|
|
|
|
const char *Name =
|
|
|
|
TLI.getTargetNodeName(getOpcode());
|
|
|
|
if (Name) return Name;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "<<Unknown Target Node>>";
|
2005-08-16 18:33:07 +00:00
|
|
|
}
|
|
|
|
|
2005-03-31 21:24:06 +00:00
|
|
|
case ISD::PCMARKER: return "PCMarker";
|
2005-11-11 16:47:30 +00:00
|
|
|
case ISD::READCYCLECOUNTER: return "ReadCycleCounter";
|
2005-05-09 04:08:27 +00:00
|
|
|
case ISD::SRCVALUE: return "SrcValue";
|
2005-08-18 03:31:02 +00:00
|
|
|
case ISD::VALUETYPE: return "ValueType";
|
2005-11-29 06:21:05 +00:00
|
|
|
case ISD::STRING: return "String";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::EntryToken: return "EntryToken";
|
2005-01-13 17:59:10 +00:00
|
|
|
case ISD::TokenFactor: return "TokenFactor";
|
Add support for AssertSext and AssertZext, folding other extensions with
them. This allows for elminination of redundant extends in the entry
blocks of functions on PowerPC.
Add support for i32 x i32 -> i64 multiplies, by recognizing when the inputs
to ISD::MUL in ExpandOp are actually just extended i32 values and not real
i64 values. this allows us to codegen
int mulhs(int a, int b) { return ((long long)a * b) >> 32; }
as:
_mulhs:
mulhw r3, r4, r3
blr
instead of:
_mulhs:
mulhwu r2, r4, r3
srawi r5, r3, 31
mullw r5, r4, r5
add r2, r2, r5
srawi r4, r4, 31
mullw r3, r4, r3
add r3, r2, r3
blr
with a similar improvement on x86.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@23147 91177308-0d34-0410-b5e6-96231b3b80d8
2005-08-30 02:44:00 +00:00
|
|
|
case ISD::AssertSext: return "AssertSext";
|
|
|
|
case ISD::AssertZext: return "AssertZext";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::Constant: return "Constant";
|
2005-08-17 00:34:06 +00:00
|
|
|
case ISD::TargetConstant: return "TargetConstant";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::ConstantFP: return "ConstantFP";
|
Teach the SelectionDAG ISel how to turn ConstantPacked values into
constant nodes with vector types. Also teach the asm printer how to print
ConstantPacked constant pool entries. This allows us to generate altivec
code such as the following, which adds a vector constantto a packed float.
LCPI1_0: <4 x float> < float 0.0e+0, float 0.0e+0, float 0.0e+0, float 1.0e+0 >
.space 4
.space 4
.space 4
.long 1065353216 ; float 1
.text
.align 4
.globl _foo
_foo:
lis r2, ha16(LCPI1_0)
la r2, lo16(LCPI1_0)(r2)
li r4, 0
lvx v0, r4, r2
lvx v1, r4, r3
vaddfp v0, v1, v0
stvx v0, r4, r3
blr
For the llvm code:
void %foo(<4 x float> * %a) {
entry:
%tmp1 = load <4 x float> * %a;
%tmp2 = add <4 x float> %tmp1, < float 0.0, float 0.0, float 0.0, float 1.0 >
store <4 x float> %tmp2, <4 x float> *%a
ret void
}
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24616 91177308-0d34-0410-b5e6-96231b3b80d8
2005-12-06 06:18:55 +00:00
|
|
|
case ISD::ConstantVec: return "ConstantVec";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::GlobalAddress: return "GlobalAddress";
|
2005-08-19 22:31:04 +00:00
|
|
|
case ISD::TargetGlobalAddress: return "TargetGlobalAddress";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::FrameIndex: return "FrameIndex";
|
2005-08-25 00:43:01 +00:00
|
|
|
case ISD::TargetFrameIndex: return "TargetFrameIndex";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::BasicBlock: return "BasicBlock";
|
2005-08-16 21:55:35 +00:00
|
|
|
case ISD::Register: return "Register";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::ExternalSymbol: return "ExternalSymbol";
|
2005-10-23 03:40:17 +00:00
|
|
|
case ISD::TargetExternalSymbol: return "TargetExternalSymbol";
|
2005-08-26 17:15:30 +00:00
|
|
|
case ISD::ConstantPool: return "ConstantPool";
|
|
|
|
case ISD::TargetConstantPool: return "TargetConstantPool";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::CopyToReg: return "CopyToReg";
|
|
|
|
case ISD::CopyFromReg: return "CopyFromReg";
|
2005-04-01 22:34:39 +00:00
|
|
|
case ISD::UNDEF: return "undef";
|
2006-01-15 08:39:35 +00:00
|
|
|
case ISD::MERGE_VALUES: return "mergevalues";
|
2006-01-26 22:24:51 +00:00
|
|
|
case ISD::INLINEASM: return "inlineasm";
|
2006-02-03 01:33:01 +00:00
|
|
|
case ISD::HANDLENODE: return "handlenode";
|
2006-01-26 22:24:51 +00:00
|
|
|
|
2005-04-02 04:58:41 +00:00
|
|
|
// Unary operators
|
|
|
|
case ISD::FABS: return "fabs";
|
|
|
|
case ISD::FNEG: return "fneg";
|
2005-04-28 21:44:03 +00:00
|
|
|
case ISD::FSQRT: return "fsqrt";
|
|
|
|
case ISD::FSIN: return "fsin";
|
|
|
|
case ISD::FCOS: return "fcos";
|
2005-04-02 04:58:41 +00:00
|
|
|
|
|
|
|
// Binary operators
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::ADD: return "add";
|
|
|
|
case ISD::SUB: return "sub";
|
|
|
|
case ISD::MUL: return "mul";
|
2005-04-05 22:36:56 +00:00
|
|
|
case ISD::MULHU: return "mulhu";
|
|
|
|
case ISD::MULHS: return "mulhs";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::SDIV: return "sdiv";
|
|
|
|
case ISD::UDIV: return "udiv";
|
|
|
|
case ISD::SREM: return "srem";
|
|
|
|
case ISD::UREM: return "urem";
|
|
|
|
case ISD::AND: return "and";
|
|
|
|
case ISD::OR: return "or";
|
|
|
|
case ISD::XOR: return "xor";
|
|
|
|
case ISD::SHL: return "shl";
|
|
|
|
case ISD::SRA: return "sra";
|
|
|
|
case ISD::SRL: return "srl";
|
2006-01-11 21:21:00 +00:00
|
|
|
case ISD::ROTL: return "rotl";
|
|
|
|
case ISD::ROTR: return "rotr";
|
2005-09-28 22:28:18 +00:00
|
|
|
case ISD::FADD: return "fadd";
|
|
|
|
case ISD::FSUB: return "fsub";
|
|
|
|
case ISD::FMUL: return "fmul";
|
|
|
|
case ISD::FDIV: return "fdiv";
|
|
|
|
case ISD::FREM: return "frem";
|
2005-11-19 00:36:38 +00:00
|
|
|
case ISD::VADD: return "vadd";
|
|
|
|
case ISD::VSUB: return "vsub";
|
|
|
|
case ISD::VMUL: return "vmul";
|
2005-09-28 22:28:18 +00:00
|
|
|
|
2005-08-09 20:20:18 +00:00
|
|
|
case ISD::SETCC: return "setcc";
|
|
|
|
case ISD::SELECT: return "select";
|
2005-08-10 20:51:12 +00:00
|
|
|
case ISD::SELECT_CC: return "select_cc";
|
2005-01-20 18:50:55 +00:00
|
|
|
case ISD::ADD_PARTS: return "add_parts";
|
|
|
|
case ISD::SUB_PARTS: return "sub_parts";
|
2005-04-02 03:30:42 +00:00
|
|
|
case ISD::SHL_PARTS: return "shl_parts";
|
|
|
|
case ISD::SRA_PARTS: return "sra_parts";
|
|
|
|
case ISD::SRL_PARTS: return "srl_parts";
|
2005-01-10 23:25:25 +00:00
|
|
|
|
2005-04-28 21:44:03 +00:00
|
|
|
// Conversion operators.
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::SIGN_EXTEND: return "sign_extend";
|
|
|
|
case ISD::ZERO_EXTEND: return "zero_extend";
|
2005-09-02 00:17:32 +00:00
|
|
|
case ISD::ANY_EXTEND: return "any_extend";
|
2005-01-15 06:17:04 +00:00
|
|
|
case ISD::SIGN_EXTEND_INREG: return "sign_extend_inreg";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::TRUNCATE: return "truncate";
|
|
|
|
case ISD::FP_ROUND: return "fp_round";
|
2005-01-15 06:17:04 +00:00
|
|
|
case ISD::FP_ROUND_INREG: return "fp_round_inreg";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::FP_EXTEND: return "fp_extend";
|
|
|
|
|
|
|
|
case ISD::SINT_TO_FP: return "sint_to_fp";
|
|
|
|
case ISD::UINT_TO_FP: return "uint_to_fp";
|
|
|
|
case ISD::FP_TO_SINT: return "fp_to_sint";
|
|
|
|
case ISD::FP_TO_UINT: return "fp_to_uint";
|
2005-12-23 00:16:34 +00:00
|
|
|
case ISD::BIT_CONVERT: return "bit_convert";
|
2005-01-10 23:25:25 +00:00
|
|
|
|
|
|
|
// Control flow instructions
|
|
|
|
case ISD::BR: return "br";
|
|
|
|
case ISD::BRCOND: return "brcond";
|
2005-04-09 03:27:28 +00:00
|
|
|
case ISD::BRCONDTWOWAY: return "brcondtwoway";
|
2005-08-16 19:49:35 +00:00
|
|
|
case ISD::BR_CC: return "br_cc";
|
|
|
|
case ISD::BRTWOWAY_CC: return "brtwoway_cc";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::RET: return "ret";
|
2005-05-12 23:51:40 +00:00
|
|
|
case ISD::CALLSEQ_START: return "callseq_start";
|
|
|
|
case ISD::CALLSEQ_END: return "callseq_end";
|
2005-01-10 23:25:25 +00:00
|
|
|
|
|
|
|
// Other operators
|
2006-01-25 18:21:52 +00:00
|
|
|
case ISD::LOAD: return "load";
|
|
|
|
case ISD::STORE: return "store";
|
|
|
|
case ISD::VLOAD: return "vload";
|
|
|
|
case ISD::EXTLOAD: return "extload";
|
|
|
|
case ISD::SEXTLOAD: return "sextload";
|
|
|
|
case ISD::ZEXTLOAD: return "zextload";
|
|
|
|
case ISD::TRUNCSTORE: return "truncstore";
|
|
|
|
case ISD::VAARG: return "vaarg";
|
|
|
|
case ISD::VACOPY: return "vacopy";
|
|
|
|
case ISD::VAEND: return "vaend";
|
|
|
|
case ISD::VASTART: return "vastart";
|
2005-01-10 23:25:25 +00:00
|
|
|
case ISD::DYNAMIC_STACKALLOC: return "dynamic_stackalloc";
|
2006-01-13 02:39:42 +00:00
|
|
|
case ISD::EXTRACT_ELEMENT: return "extract_element";
|
|
|
|
case ISD::BUILD_PAIR: return "build_pair";
|
|
|
|
case ISD::STACKSAVE: return "stacksave";
|
|
|
|
case ISD::STACKRESTORE: return "stackrestore";
|
|
|
|
|
|
|
|
// Block memory operations.
|
2005-01-11 05:57:01 +00:00
|
|
|
case ISD::MEMSET: return "memset";
|
|
|
|
case ISD::MEMCPY: return "memcpy";
|
|
|
|
case ISD::MEMMOVE: return "memmove";
|
2005-01-07 07:46:32 +00:00
|
|
|
|
2006-01-16 08:07:10 +00:00
|
|
|
// Bit manipulation
|
|
|
|
case ISD::BSWAP: return "bswap";
|
2005-05-11 04:50:30 +00:00
|
|
|
case ISD::CTPOP: return "ctpop";
|
|
|
|
case ISD::CTTZ: return "cttz";
|
|
|
|
case ISD::CTLZ: return "ctlz";
|
|
|
|
|
|
|
|
// IO Intrinsics
|
2005-05-09 20:22:17 +00:00
|
|
|
case ISD::READPORT: return "readport";
|
|
|
|
case ISD::WRITEPORT: return "writeport";
|
|
|
|
case ISD::READIO: return "readio";
|
|
|
|
case ISD::WRITEIO: return "writeio";
|
|
|
|
|
2005-11-29 06:21:05 +00:00
|
|
|
// Debug info
|
|
|
|
case ISD::LOCATION: return "location";
|
2005-12-16 22:45:29 +00:00
|
|
|
case ISD::DEBUG_LOC: return "debug_loc";
|
2006-01-05 01:25:28 +00:00
|
|
|
case ISD::DEBUG_LABEL: return "debug_label";
|
2005-11-29 06:21:05 +00:00
|
|
|
|
2005-08-09 20:20:18 +00:00
|
|
|
case ISD::CONDCODE:
|
|
|
|
switch (cast<CondCodeSDNode>(this)->get()) {
|
2005-01-10 23:25:25 +00:00
|
|
|
default: assert(0 && "Unknown setcc condition!");
|
2005-08-09 20:20:18 +00:00
|
|
|
case ISD::SETOEQ: return "setoeq";
|
|
|
|
case ISD::SETOGT: return "setogt";
|
|
|
|
case ISD::SETOGE: return "setoge";
|
|
|
|
case ISD::SETOLT: return "setolt";
|
|
|
|
case ISD::SETOLE: return "setole";
|
|
|
|
case ISD::SETONE: return "setone";
|
|
|
|
|
|
|
|
case ISD::SETO: return "seto";
|
|
|
|
case ISD::SETUO: return "setuo";
|
|
|
|
case ISD::SETUEQ: return "setue";
|
|
|
|
case ISD::SETUGT: return "setugt";
|
|
|
|
case ISD::SETUGE: return "setuge";
|
|
|
|
case ISD::SETULT: return "setult";
|
|
|
|
case ISD::SETULE: return "setule";
|
|
|
|
case ISD::SETUNE: return "setune";
|
|
|
|
|
|
|
|
case ISD::SETEQ: return "seteq";
|
|
|
|
case ISD::SETGT: return "setgt";
|
|
|
|
case ISD::SETGE: return "setge";
|
|
|
|
case ISD::SETLT: return "setlt";
|
|
|
|
case ISD::SETLE: return "setle";
|
|
|
|
case ISD::SETNE: return "setne";
|
2005-01-10 23:25:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
|
2005-08-16 18:33:07 +00:00
|
|
|
void SDNode::dump() const { dump(0); }
|
|
|
|
void SDNode::dump(const SelectionDAG *G) const {
|
2005-01-07 07:46:32 +00:00
|
|
|
std::cerr << (void*)this << ": ";
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
|
|
|
|
if (i) std::cerr << ",";
|
2005-01-15 07:14:32 +00:00
|
|
|
if (getValueType(i) == MVT::Other)
|
|
|
|
std::cerr << "ch";
|
|
|
|
else
|
|
|
|
std::cerr << MVT::getValueTypeString(getValueType(i));
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
2005-08-16 18:33:07 +00:00
|
|
|
std::cerr << " = " << getOperationName(G);
|
2005-01-07 07:46:32 +00:00
|
|
|
|
|
|
|
std::cerr << " ";
|
|
|
|
for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
|
|
|
|
if (i) std::cerr << ", ";
|
|
|
|
std::cerr << (void*)getOperand(i).Val;
|
|
|
|
if (unsigned RN = getOperand(i).ResNo)
|
|
|
|
std::cerr << ":" << RN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(this)) {
|
|
|
|
std::cerr << "<" << CSDN->getValue() << ">";
|
|
|
|
} else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(this)) {
|
|
|
|
std::cerr << "<" << CSDN->getValue() << ">";
|
2005-04-21 22:36:52 +00:00
|
|
|
} else if (const GlobalAddressSDNode *GADN =
|
2005-01-07 07:46:32 +00:00
|
|
|
dyn_cast<GlobalAddressSDNode>(this)) {
|
2005-11-30 02:04:11 +00:00
|
|
|
int offset = GADN->getOffset();
|
2005-01-07 07:46:32 +00:00
|
|
|
std::cerr << "<";
|
|
|
|
WriteAsOperand(std::cerr, GADN->getGlobal()) << ">";
|
2005-11-30 02:04:11 +00:00
|
|
|
if (offset > 0)
|
|
|
|
std::cerr << " + " << offset;
|
|
|
|
else
|
|
|
|
std::cerr << " " << offset;
|
2005-04-22 04:01:18 +00:00
|
|
|
} else if (const FrameIndexSDNode *FIDN = dyn_cast<FrameIndexSDNode>(this)) {
|
2005-01-07 07:46:32 +00:00
|
|
|
std::cerr << "<" << FIDN->getIndex() << ">";
|
|
|
|
} else if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(this)){
|
2005-08-26 17:15:30 +00:00
|
|
|
std::cerr << "<" << *CP->get() << ">";
|
2005-04-22 04:01:18 +00:00
|
|
|
} else if (const BasicBlockSDNode *BBDN = dyn_cast<BasicBlockSDNode>(this)) {
|
2005-01-07 07:46:32 +00:00
|
|
|
std::cerr << "<";
|
|
|
|
const Value *LBB = (const Value*)BBDN->getBasicBlock()->getBasicBlock();
|
|
|
|
if (LBB)
|
|
|
|
std::cerr << LBB->getName() << " ";
|
|
|
|
std::cerr << (const void*)BBDN->getBasicBlock() << ">";
|
2005-08-19 21:34:13 +00:00
|
|
|
} else if (const RegisterSDNode *R = dyn_cast<RegisterSDNode>(this)) {
|
2006-01-11 22:13:48 +00:00
|
|
|
if (G && R->getReg() && MRegisterInfo::isPhysicalRegister(R->getReg())) {
|
2005-08-19 21:21:16 +00:00
|
|
|
std::cerr << " " <<G->getTarget().getRegisterInfo()->getName(R->getReg());
|
|
|
|
} else {
|
|
|
|
std::cerr << " #" << R->getReg();
|
|
|
|
}
|
2005-01-07 07:46:32 +00:00
|
|
|
} else if (const ExternalSymbolSDNode *ES =
|
|
|
|
dyn_cast<ExternalSymbolSDNode>(this)) {
|
|
|
|
std::cerr << "'" << ES->getSymbol() << "'";
|
2005-05-09 04:08:27 +00:00
|
|
|
} else if (const SrcValueSDNode *M = dyn_cast<SrcValueSDNode>(this)) {
|
|
|
|
if (M->getValue())
|
|
|
|
std::cerr << "<" << M->getValue() << ":" << M->getOffset() << ">";
|
|
|
|
else
|
|
|
|
std::cerr << "<null:" << M->getOffset() << ">";
|
2005-08-18 03:31:02 +00:00
|
|
|
} else if (const VTSDNode *N = dyn_cast<VTSDNode>(this)) {
|
|
|
|
std::cerr << ":" << getValueTypeString(N->getVT());
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-09 23:47:37 +00:00
|
|
|
static void DumpNodes(const SDNode *N, unsigned indent, const SelectionDAG *G) {
|
2005-01-09 20:38:33 +00:00
|
|
|
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i)
|
|
|
|
if (N->getOperand(i).Val->hasOneUse())
|
2005-08-16 18:33:07 +00:00
|
|
|
DumpNodes(N->getOperand(i).Val, indent+2, G);
|
2005-01-09 20:38:33 +00:00
|
|
|
else
|
|
|
|
std::cerr << "\n" << std::string(indent+2, ' ')
|
|
|
|
<< (void*)N->getOperand(i).Val << ": <multiple use>";
|
2005-04-21 22:36:52 +00:00
|
|
|
|
2005-01-09 20:38:33 +00:00
|
|
|
|
|
|
|
std::cerr << "\n" << std::string(indent, ' ');
|
2005-08-16 18:33:07 +00:00
|
|
|
N->dump(G);
|
2005-01-09 20:38:33 +00:00
|
|
|
}
|
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
void SelectionDAG::dump() const {
|
|
|
|
std::cerr << "SelectionDAG has " << AllNodes.size() << " nodes:";
|
2005-11-09 23:47:37 +00:00
|
|
|
std::vector<const SDNode*> Nodes;
|
|
|
|
for (allnodes_const_iterator I = allnodes_begin(), E = allnodes_end();
|
|
|
|
I != E; ++I)
|
|
|
|
Nodes.push_back(I);
|
|
|
|
|
2005-01-09 20:26:36 +00:00
|
|
|
std::sort(Nodes.begin(), Nodes.end());
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = Nodes.size(); i != e; ++i) {
|
2005-01-09 20:38:33 +00:00
|
|
|
if (!Nodes[i]->hasOneUse() && Nodes[i] != getRoot().Val)
|
2005-08-16 18:33:07 +00:00
|
|
|
DumpNodes(Nodes[i], 2, this);
|
2005-01-07 07:46:32 +00:00
|
|
|
}
|
2005-01-09 20:38:33 +00:00
|
|
|
|
2005-08-16 18:33:07 +00:00
|
|
|
DumpNodes(getRoot().Val, 2, this);
|
2005-01-09 20:38:33 +00:00
|
|
|
|
2005-01-07 07:46:32 +00:00
|
|
|
std::cerr << "\n\n";
|
|
|
|
}
|
|
|
|
|