mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-15 04:30:12 +00:00
[DAG] Expose NoSignedWrap, NoUnsignedWrap and Exact flags to SelectionDAG.
This patch modifies SelectionDAGBuilder to construct SDNodes with associated NoSignedWrap, NoUnsignedWrap and Exact flags coming from IR BinaryOperator instructions. Added a new SDNode type called 'BinaryWithFlagsSDNode' to allow accessing nsw/nuw/exact flags during codegen. Patch by Marcello Maggioni. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210467 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a2bc6951a0
commit
bc72c8f0d8
@ -612,14 +612,14 @@ public:
|
|||||||
///
|
///
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT);
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT);
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N);
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N);
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2);
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2,
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT,
|
bool nuw = false, bool nsw = false, bool exact = false);
|
||||||
SDValue N1, SDValue N2, SDValue N3);
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2,
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT,
|
SDValue N3);
|
||||||
SDValue N1, SDValue N2, SDValue N3, SDValue N4);
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2,
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT,
|
SDValue N3, SDValue N4);
|
||||||
SDValue N1, SDValue N2, SDValue N3, SDValue N4,
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1, SDValue N2,
|
||||||
SDValue N5);
|
SDValue N3, SDValue N4, SDValue N5);
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, ArrayRef<SDUse> Ops);
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT, ArrayRef<SDUse> Ops);
|
||||||
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT,
|
SDValue getNode(unsigned Opcode, SDLoc DL, EVT VT,
|
||||||
ArrayRef<SDValue> Ops);
|
ArrayRef<SDValue> Ops);
|
||||||
@ -927,7 +927,9 @@ public:
|
|||||||
|
|
||||||
/// getNodeIfExists - Get the specified node if it's already available, or
|
/// getNodeIfExists - Get the specified node if it's already available, or
|
||||||
/// else return NULL.
|
/// else return NULL.
|
||||||
SDNode *getNodeIfExists(unsigned Opcode, SDVTList VTs, ArrayRef<SDValue> Ops);
|
SDNode *getNodeIfExists(unsigned Opcode, SDVTList VTs, ArrayRef<SDValue> Ops,
|
||||||
|
bool nuw = false, bool nsw = false,
|
||||||
|
bool exact = false);
|
||||||
|
|
||||||
/// getDbgValue - Creates a SDDbgValue node.
|
/// getDbgValue - Creates a SDDbgValue node.
|
||||||
///
|
///
|
||||||
@ -1184,6 +1186,10 @@ private:
|
|||||||
|
|
||||||
void allnodes_clear();
|
void allnodes_clear();
|
||||||
|
|
||||||
|
BinarySDNode *GetBinarySDNode(unsigned Opcode, SDLoc DL, SDVTList VTs,
|
||||||
|
SDValue N1, SDValue N2, bool nuw, bool nsw,
|
||||||
|
bool exact);
|
||||||
|
|
||||||
/// VTList - List of non-single value types.
|
/// VTList - List of non-single value types.
|
||||||
FoldingSet<SDVTListNode> VTListMap;
|
FoldingSet<SDVTListNode> VTListMap;
|
||||||
|
|
||||||
|
@ -49,6 +49,24 @@ template <typename T> struct DenseMapInfo;
|
|||||||
template <typename T> struct simplify_type;
|
template <typename T> struct simplify_type;
|
||||||
template <typename T> struct ilist_traits;
|
template <typename T> struct ilist_traits;
|
||||||
|
|
||||||
|
/// isBinOpWithFlags - Returns true if the opcode is a binary operation
|
||||||
|
/// with flags.
|
||||||
|
static bool isBinOpWithFlags(unsigned Opcode) {
|
||||||
|
switch (Opcode) {
|
||||||
|
case ISD::SDIV:
|
||||||
|
case ISD::UDIV:
|
||||||
|
case ISD::SRA:
|
||||||
|
case ISD::SRL:
|
||||||
|
case ISD::MUL:
|
||||||
|
case ISD::ADD:
|
||||||
|
case ISD::SUB:
|
||||||
|
case ISD::SHL:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr,
|
void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr,
|
||||||
bool force = false);
|
bool force = false);
|
||||||
|
|
||||||
@ -939,6 +957,36 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// BinaryWithFlagsSDNode - This class is an extension of BinarySDNode
|
||||||
|
/// used from those opcodes that have associated extra flags.
|
||||||
|
class BinaryWithFlagsSDNode : public BinarySDNode {
|
||||||
|
enum { NUW = (1 << 0), NSW = (1 << 1), EXACT = (1 << 2) };
|
||||||
|
|
||||||
|
public:
|
||||||
|
BinaryWithFlagsSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTs,
|
||||||
|
SDValue X, SDValue Y)
|
||||||
|
: BinarySDNode(Opc, Order, dl, VTs, X, Y) {}
|
||||||
|
/// getRawSubclassData - Return the SubclassData value, which contains an
|
||||||
|
/// encoding of the flags.
|
||||||
|
/// This function should be used to add subclass data to the NodeID value.
|
||||||
|
unsigned getRawSubclassData() const { return SubclassData; }
|
||||||
|
void setHasNoUnsignedWrap(bool b) {
|
||||||
|
SubclassData = (SubclassData & ~NUW) | (b ? NUW : 0);
|
||||||
|
}
|
||||||
|
void setHasNoSignedWrap(bool b) {
|
||||||
|
SubclassData = (SubclassData & ~NSW) | (b ? NSW : 0);
|
||||||
|
}
|
||||||
|
void setIsExact(bool b) {
|
||||||
|
SubclassData = (SubclassData & ~EXACT) | (b ? EXACT : 0);
|
||||||
|
}
|
||||||
|
bool hasNoUnsignedWrap() const { return SubclassData & NUW; }
|
||||||
|
bool hasNoSignedWrap() const { return SubclassData & NSW; }
|
||||||
|
bool isExact() const { return SubclassData & EXACT; }
|
||||||
|
static bool classof(const SDNode *N) {
|
||||||
|
return isBinOpWithFlags(N->getOpcode());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// TernarySDNode - This class is used for three-operand SDNodes. This is solely
|
/// TernarySDNode - This class is used for three-operand SDNodes. This is solely
|
||||||
/// to allow co-allocation of node operands with the node itself.
|
/// to allow co-allocation of node operands with the node itself.
|
||||||
class TernarySDNode : public SDNode {
|
class TernarySDNode : public SDNode {
|
||||||
|
@ -1325,9 +1325,16 @@ SDValue DAGCombiner::combine(SDNode *N) {
|
|||||||
|
|
||||||
// Constant operands are canonicalized to RHS.
|
// Constant operands are canonicalized to RHS.
|
||||||
if (isa<ConstantSDNode>(N0) || !isa<ConstantSDNode>(N1)) {
|
if (isa<ConstantSDNode>(N0) || !isa<ConstantSDNode>(N1)) {
|
||||||
SDValue Ops[] = { N1, N0 };
|
SDValue Ops[] = {N1, N0};
|
||||||
SDNode *CSENode = DAG.getNodeIfExists(N->getOpcode(), N->getVTList(),
|
SDNode *CSENode;
|
||||||
Ops);
|
if (const BinaryWithFlagsSDNode *BinNode =
|
||||||
|
dyn_cast<BinaryWithFlagsSDNode>(N)) {
|
||||||
|
CSENode = DAG.getNodeIfExists(
|
||||||
|
N->getOpcode(), N->getVTList(), Ops, BinNode->hasNoUnsignedWrap(),
|
||||||
|
BinNode->hasNoSignedWrap(), BinNode->isExact());
|
||||||
|
} else {
|
||||||
|
CSENode = DAG.getNodeIfExists(N->getOpcode(), N->getVTList(), Ops);
|
||||||
|
}
|
||||||
if (CSENode)
|
if (CSENode)
|
||||||
return SDValue(CSENode, 0);
|
return SDValue(CSENode, 0);
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "llvm/Target/TargetSelectionDAGInfo.h"
|
#include "llvm/Target/TargetSelectionDAGInfo.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
/// makeVTList - Return an instance of the SDVTList struct initialized with the
|
/// makeVTList - Return an instance of the SDVTList struct initialized with the
|
||||||
@ -381,6 +382,20 @@ static void AddNodeIDOperands(FoldingSetNodeID &ID,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddBinaryNodeIDCustom(FoldingSetNodeID &ID, bool nuw, bool nsw,
|
||||||
|
bool exact) {
|
||||||
|
ID.AddBoolean(nuw);
|
||||||
|
ID.AddBoolean(nsw);
|
||||||
|
ID.AddBoolean(exact);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AddBinaryNodeIDCustom - Add BinarySDNodes special infos
|
||||||
|
static void AddBinaryNodeIDCustom(FoldingSetNodeID &ID, unsigned Opcode,
|
||||||
|
bool nuw, bool nsw, bool exact) {
|
||||||
|
if (isBinOpWithFlags(Opcode))
|
||||||
|
AddBinaryNodeIDCustom(ID, nuw, nsw, exact);
|
||||||
|
}
|
||||||
|
|
||||||
static void AddNodeIDNode(FoldingSetNodeID &ID, unsigned short OpC,
|
static void AddNodeIDNode(FoldingSetNodeID &ID, unsigned short OpC,
|
||||||
SDVTList VTList, ArrayRef<SDValue> OpList) {
|
SDVTList VTList, ArrayRef<SDValue> OpList) {
|
||||||
AddNodeIDOpcode(ID, OpC);
|
AddNodeIDOpcode(ID, OpC);
|
||||||
@ -473,6 +488,19 @@ static void AddNodeIDCustom(FoldingSetNodeID &ID, const SDNode *N) {
|
|||||||
ID.AddInteger(ST->getPointerInfo().getAddrSpace());
|
ID.AddInteger(ST->getPointerInfo().getAddrSpace());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ISD::SDIV:
|
||||||
|
case ISD::UDIV:
|
||||||
|
case ISD::SRA:
|
||||||
|
case ISD::SRL:
|
||||||
|
case ISD::MUL:
|
||||||
|
case ISD::ADD:
|
||||||
|
case ISD::SUB:
|
||||||
|
case ISD::SHL: {
|
||||||
|
const BinaryWithFlagsSDNode *BinNode = cast<BinaryWithFlagsSDNode>(N);
|
||||||
|
AddBinaryNodeIDCustom(ID, N->getOpcode(), BinNode->hasNoUnsignedWrap(),
|
||||||
|
BinNode->hasNoSignedWrap(), BinNode->isExact());
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ISD::ATOMIC_CMP_SWAP:
|
case ISD::ATOMIC_CMP_SWAP:
|
||||||
case ISD::ATOMIC_SWAP:
|
case ISD::ATOMIC_SWAP:
|
||||||
case ISD::ATOMIC_LOAD_ADD:
|
case ISD::ATOMIC_LOAD_ADD:
|
||||||
@ -926,6 +954,25 @@ void SelectionDAG::allnodes_clear() {
|
|||||||
DeallocateNode(AllNodes.begin());
|
DeallocateNode(AllNodes.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinarySDNode *SelectionDAG::GetBinarySDNode(unsigned Opcode, SDLoc DL,
|
||||||
|
SDVTList VTs, SDValue N1,
|
||||||
|
SDValue N2, bool nuw, bool nsw,
|
||||||
|
bool exact) {
|
||||||
|
if (isBinOpWithFlags(Opcode)) {
|
||||||
|
BinaryWithFlagsSDNode *FN = new (NodeAllocator) BinaryWithFlagsSDNode(
|
||||||
|
Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs, N1, N2);
|
||||||
|
FN->setHasNoUnsignedWrap(nuw);
|
||||||
|
FN->setHasNoSignedWrap(nsw);
|
||||||
|
FN->setIsExact(exact);
|
||||||
|
|
||||||
|
return FN;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinarySDNode *N = new (NodeAllocator)
|
||||||
|
BinarySDNode(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs, N1, N2);
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
void SelectionDAG::clear() {
|
void SelectionDAG::clear() {
|
||||||
allnodes_clear();
|
allnodes_clear();
|
||||||
OperandAllocator.Reset();
|
OperandAllocator.Reset();
|
||||||
@ -2936,7 +2983,7 @@ SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, EVT VT,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
|
SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
|
||||||
SDValue N2) {
|
SDValue N2, bool nuw, bool nsw, bool exact) {
|
||||||
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.getNode());
|
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1.getNode());
|
||||||
ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2.getNode());
|
ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2.getNode());
|
||||||
switch (Opcode) {
|
switch (Opcode) {
|
||||||
@ -3376,22 +3423,25 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL, EVT VT, SDValue N1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Memoize this node if possible.
|
// Memoize this node if possible.
|
||||||
SDNode *N;
|
BinarySDNode *N;
|
||||||
SDVTList VTs = getVTList(VT);
|
SDVTList VTs = getVTList(VT);
|
||||||
|
const bool BinOpHasFlags = isBinOpWithFlags(Opcode);
|
||||||
if (VT != MVT::Glue) {
|
if (VT != MVT::Glue) {
|
||||||
SDValue Ops[] = { N1, N2 };
|
SDValue Ops[] = {N1, N2};
|
||||||
FoldingSetNodeID ID;
|
FoldingSetNodeID ID;
|
||||||
AddNodeIDNode(ID, Opcode, VTs, Ops);
|
AddNodeIDNode(ID, Opcode, VTs, Ops);
|
||||||
|
if (BinOpHasFlags)
|
||||||
|
AddBinaryNodeIDCustom(ID, Opcode, nuw, nsw, exact);
|
||||||
void *IP = nullptr;
|
void *IP = nullptr;
|
||||||
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
|
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
|
||||||
return SDValue(E, 0);
|
return SDValue(E, 0);
|
||||||
|
|
||||||
N = new (NodeAllocator) BinarySDNode(Opcode, DL.getIROrder(),
|
N = GetBinarySDNode(Opcode, DL, VTs, N1, N2, nuw, nsw, exact);
|
||||||
DL.getDebugLoc(), VTs, N1, N2);
|
|
||||||
CSEMap.InsertNode(N, IP);
|
CSEMap.InsertNode(N, IP);
|
||||||
} else {
|
} else {
|
||||||
N = new (NodeAllocator) BinarySDNode(Opcode, DL.getIROrder(),
|
|
||||||
DL.getDebugLoc(), VTs, N1, N2);
|
N = GetBinarySDNode(Opcode, DL, VTs, N1, N2, nuw, nsw, exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
AllNodes.push_back(N);
|
AllNodes.push_back(N);
|
||||||
@ -5606,10 +5656,13 @@ SelectionDAG::getTargetInsertSubreg(int SRIdx, SDLoc DL, EVT VT,
|
|||||||
/// getNodeIfExists - Get the specified node if it's already available, or
|
/// getNodeIfExists - Get the specified node if it's already available, or
|
||||||
/// else return NULL.
|
/// else return NULL.
|
||||||
SDNode *SelectionDAG::getNodeIfExists(unsigned Opcode, SDVTList VTList,
|
SDNode *SelectionDAG::getNodeIfExists(unsigned Opcode, SDVTList VTList,
|
||||||
ArrayRef<SDValue> Ops) {
|
ArrayRef<SDValue> Ops, bool nuw, bool nsw,
|
||||||
if (VTList.VTs[VTList.NumVTs-1] != MVT::Glue) {
|
bool exact) {
|
||||||
|
if (VTList.VTs[VTList.NumVTs - 1] != MVT::Glue) {
|
||||||
FoldingSetNodeID ID;
|
FoldingSetNodeID ID;
|
||||||
AddNodeIDNode(ID, Opcode, VTList, Ops);
|
AddNodeIDNode(ID, Opcode, VTList, Ops);
|
||||||
|
if (isBinOpWithFlags(Opcode))
|
||||||
|
AddBinaryNodeIDCustom(ID, nuw, nsw, exact);
|
||||||
void *IP = nullptr;
|
void *IP = nullptr;
|
||||||
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
|
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
|
||||||
return E;
|
return E;
|
||||||
|
@ -2784,8 +2784,22 @@ void SelectionDAGBuilder::visitFSub(const User &I) {
|
|||||||
void SelectionDAGBuilder::visitBinary(const User &I, unsigned OpCode) {
|
void SelectionDAGBuilder::visitBinary(const User &I, unsigned OpCode) {
|
||||||
SDValue Op1 = getValue(I.getOperand(0));
|
SDValue Op1 = getValue(I.getOperand(0));
|
||||||
SDValue Op2 = getValue(I.getOperand(1));
|
SDValue Op2 = getValue(I.getOperand(1));
|
||||||
setValue(&I, DAG.getNode(OpCode, getCurSDLoc(),
|
|
||||||
Op1.getValueType(), Op1, Op2));
|
bool nuw = false;
|
||||||
|
bool nsw = false;
|
||||||
|
bool exact = false;
|
||||||
|
if (const OverflowingBinaryOperator *OFBinOp =
|
||||||
|
dyn_cast<const OverflowingBinaryOperator>(&I)) {
|
||||||
|
nuw = OFBinOp->hasNoUnsignedWrap();
|
||||||
|
nsw = OFBinOp->hasNoSignedWrap();
|
||||||
|
}
|
||||||
|
if (const PossiblyExactOperator *ExactOp =
|
||||||
|
dyn_cast<const PossiblyExactOperator>(&I))
|
||||||
|
exact = ExactOp->isExact();
|
||||||
|
|
||||||
|
SDValue BinNodeValue = DAG.getNode(OpCode, getCurSDLoc(), Op1.getValueType(),
|
||||||
|
Op1, Op2, nuw, nsw, exact);
|
||||||
|
setValue(&I, BinNodeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
|
void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
|
||||||
@ -2816,8 +2830,25 @@ void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) {
|
|||||||
Op2 = DAG.getZExtOrTrunc(Op2, DL, MVT::i32);
|
Op2 = DAG.getZExtOrTrunc(Op2, DL, MVT::i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(&I, DAG.getNode(Opcode, getCurSDLoc(),
|
bool nuw = false;
|
||||||
Op1.getValueType(), Op1, Op2));
|
bool nsw = false;
|
||||||
|
bool exact = false;
|
||||||
|
|
||||||
|
if (Opcode == ISD::SRL || Opcode == ISD::SRA || Opcode == ISD::SHL) {
|
||||||
|
|
||||||
|
if (const OverflowingBinaryOperator *OFBinOp =
|
||||||
|
dyn_cast<const OverflowingBinaryOperator>(&I)) {
|
||||||
|
nuw = OFBinOp->hasNoUnsignedWrap();
|
||||||
|
nsw = OFBinOp->hasNoSignedWrap();
|
||||||
|
}
|
||||||
|
if (const PossiblyExactOperator *ExactOp =
|
||||||
|
dyn_cast<const PossiblyExactOperator>(&I))
|
||||||
|
exact = ExactOp->isExact();
|
||||||
|
}
|
||||||
|
|
||||||
|
SDValue Res = DAG.getNode(Opcode, getCurSDLoc(), Op1.getValueType(), Op1, Op2,
|
||||||
|
nuw, nsw, exact);
|
||||||
|
setValue(&I, Res);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionDAGBuilder::visitSDiv(const User &I) {
|
void SelectionDAGBuilder::visitSDiv(const User &I) {
|
||||||
|
@ -2617,7 +2617,8 @@ SDValue TargetLowering::BuildExactSDIV(SDValue Op1, SDValue Op2, SDLoc dl,
|
|||||||
if (ShAmt) {
|
if (ShAmt) {
|
||||||
// TODO: For UDIV use SRL instead of SRA.
|
// TODO: For UDIV use SRL instead of SRA.
|
||||||
SDValue Amt = DAG.getConstant(ShAmt, getShiftAmountTy(Op1.getValueType()));
|
SDValue Amt = DAG.getConstant(ShAmt, getShiftAmountTy(Op1.getValueType()));
|
||||||
Op1 = DAG.getNode(ISD::SRA, dl, Op1.getValueType(), Op1, Amt);
|
Op1 = DAG.getNode(ISD::SRA, dl, Op1.getValueType(), Op1, Amt, false, false,
|
||||||
|
true);
|
||||||
d = d.ashr(ShAmt);
|
d = d.ashr(ShAmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
test/CodeGen/X86/2014-05-30-CombineAddNSW.ll
Normal file
20
test/CodeGen/X86/2014-05-30-CombineAddNSW.ll
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
; RUN: llc < %s -march=x86-64 | FileCheck %s
|
||||||
|
; CHECK: addl
|
||||||
|
|
||||||
|
; The two additions are the same , but have different flags.
|
||||||
|
; In theory this code should never be generated by the frontend, but this
|
||||||
|
; tries to test that two identical instructions with two different flags
|
||||||
|
; actually generate two different nodes.
|
||||||
|
;
|
||||||
|
; Normally the combiner would see this condition without the flags
|
||||||
|
; and optimize the result of the sub into a register clear
|
||||||
|
; (the final result would be 0). With the different flags though the combiner
|
||||||
|
; needs to keep the add + sub nodes, because the two nodes result as different
|
||||||
|
; nodes and so cannot assume that the subtraction of the two nodes
|
||||||
|
; generates 0 as result
|
||||||
|
define i32 @foo(i32 %a, i32 %b) {
|
||||||
|
%1 = add i32 %a, %b
|
||||||
|
%2 = add nsw i32 %a, %b
|
||||||
|
%3 = sub i32 %1, %2
|
||||||
|
ret i32 %3
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user