[Hexagon] Simplify (+fix) instruction selection for indexed loads/stores

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273733 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Krzysztof Parzyszek 2016-06-24 21:27:17 +00:00
parent cb2753f32e
commit 99719f40ee
2 changed files with 213 additions and 308 deletions

View File

@ -94,11 +94,6 @@ public:
void SelectLoad(SDNode *N);
void SelectBaseOffsetLoad(LoadSDNode *LD, SDLoc dl);
void SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl);
void SelectIndexedLoadZeroExtend64(LoadSDNode *LD, unsigned Opcode,
const SDLoc &dl);
void SelectIndexedLoadSignExtend64(LoadSDNode *LD, unsigned Opcode,
const SDLoc &dl);
void SelectBaseOffsetStore(StoreSDNode *ST, SDLoc dl);
void SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl);
void SelectStore(SDNode *N);
void SelectSHL(SDNode *N);
@ -241,128 +236,11 @@ static bool doesIntrinsicReturnPredicate(unsigned ID) {
}
}
void HexagonDAGToDAGISel::SelectIndexedLoadSignExtend64(LoadSDNode *LD,
unsigned Opcode,
const SDLoc &dl) {
SDValue Chain = LD->getChain();
EVT LoadedVT = LD->getMemoryVT();
SDValue Base = LD->getBasePtr();
SDValue Offset = LD->getOffset();
SDNode *OffsetNode = Offset.getNode();
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
if (HII->isValidAutoIncImm(LoadedVT, Val)) {
SDValue TargetConst = CurDAG->getTargetConstant(Val, dl, MVT::i32);
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32,
MVT::Other, Base, TargetConst,
Chain);
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::A2_sxtw, dl, MVT::i64,
SDValue(Result_1, 0));
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = LD->getMemOperand();
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
const SDValue Froms[] = { SDValue(LD, 0),
SDValue(LD, 1),
SDValue(LD, 2) };
const SDValue Tos[] = { SDValue(Result_2, 0),
SDValue(Result_1, 1),
SDValue(Result_1, 2) };
ReplaceUses(Froms, Tos, 3);
CurDAG->RemoveDeadNode(LD);
return;
}
SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, dl, MVT::i32);
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Other,
Base, TargetConst0, Chain);
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::A2_sxtw, dl, MVT::i64,
SDValue(Result_1, 0));
SDNode* Result_3 = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
Base, TargetConstVal,
SDValue(Result_1, 1));
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = LD->getMemOperand();
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
const SDValue Froms[] = { SDValue(LD, 0),
SDValue(LD, 1),
SDValue(LD, 2) };
const SDValue Tos[] = { SDValue(Result_2, 0),
SDValue(Result_3, 0),
SDValue(Result_1, 1) };
ReplaceUses(Froms, Tos, 3);
CurDAG->RemoveDeadNode(LD);
}
void HexagonDAGToDAGISel::SelectIndexedLoadZeroExtend64(LoadSDNode *LD,
unsigned Opcode,
const SDLoc &dl) {
SDValue Chain = LD->getChain();
EVT LoadedVT = LD->getMemoryVT();
SDValue Base = LD->getBasePtr();
SDValue Offset = LD->getOffset();
SDNode *OffsetNode = Offset.getNode();
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
if (HII->isValidAutoIncImm(LoadedVT, Val)) {
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, dl, MVT::i32);
SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32,
MVT::i32, MVT::Other, Base,
TargetConstVal, Chain);
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::A4_combineir, dl,
MVT::i64, MVT::Other,
TargetConst0,
SDValue(Result_1,0));
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = LD->getMemOperand();
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
const SDValue Froms[] = { SDValue(LD, 0),
SDValue(LD, 1),
SDValue(LD, 2) };
const SDValue Tos[] = { SDValue(Result_2, 0),
SDValue(Result_1, 1),
SDValue(Result_1, 2) };
ReplaceUses(Froms, Tos, 3);
CurDAG->RemoveDeadNode(LD);
return;
}
// Generate an indirect load.
SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, dl, MVT::i32);
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32,
MVT::Other, Base, TargetConst0,
Chain);
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::A4_combineir, dl,
MVT::i64, MVT::Other,
TargetConst0,
SDValue(Result_1,0));
// Add offset to base.
SDNode* Result_3 = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
Base, TargetConstVal,
SDValue(Result_1, 1));
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = LD->getMemOperand();
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
const SDValue Froms[] = { SDValue(LD, 0),
SDValue(LD, 1),
SDValue(LD, 2) };
const SDValue Tos[] = { SDValue(Result_2, 0), // Load value.
SDValue(Result_3, 0), // New address.
SDValue(Result_1, 1) };
ReplaceUses(Froms, Tos, 3);
CurDAG->RemoveDeadNode(LD);
return;
}
void HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl) {
SDValue Chain = LD->getChain();
SDValue Base = LD->getBasePtr();
SDValue Offset = LD->getOffset();
SDNode *OffsetNode = Offset.getNode();
// Get the constant value.
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
int32_t Inc = cast<ConstantSDNode>(Offset.getNode())->getSExtValue();
EVT LoadedVT = LD->getMemoryVT();
unsigned Opcode = 0;
@ -370,119 +248,110 @@ void HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl) {
// loads.
ISD::LoadExtType ExtType = LD->getExtensionType();
bool IsZeroExt = (ExtType == ISD::ZEXTLOAD || ExtType == ISD::EXTLOAD);
bool HasVecOffset = false;
bool IsValidInc = HII->isValidAutoIncImm(LoadedVT, Inc);
// Figure out the opcode.
if (LoadedVT == MVT::i64) {
if (HII->isValidAutoIncImm(LoadedVT, Val))
Opcode = Hexagon::L2_loadrd_pi;
assert(LoadedVT.isSimple());
switch (LoadedVT.getSimpleVT().SimpleTy) {
case MVT::i8:
if (IsZeroExt)
Opcode = IsValidInc ? Hexagon::L2_loadrub_pi : Hexagon::L2_loadrub_io;
else
Opcode = Hexagon::L2_loadrd_io;
} else if (LoadedVT == MVT::i32) {
if (HII->isValidAutoIncImm(LoadedVT, Val))
Opcode = Hexagon::L2_loadri_pi;
Opcode = IsValidInc ? Hexagon::L2_loadrb_pi : Hexagon::L2_loadrb_io;
break;
case MVT::i16:
if (IsZeroExt)
Opcode = IsValidInc ? Hexagon::L2_loadruh_pi : Hexagon::L2_loadruh_io;
else
Opcode = Hexagon::L2_loadri_io;
} else if (LoadedVT == MVT::i16) {
if (HII->isValidAutoIncImm(LoadedVT, Val))
Opcode = IsZeroExt ? Hexagon::L2_loadruh_pi : Hexagon::L2_loadrh_pi;
Opcode = IsValidInc ? Hexagon::L2_loadrh_pi : Hexagon::L2_loadrh_io;
break;
case MVT::i32:
Opcode = IsValidInc ? Hexagon::L2_loadri_pi : Hexagon::L2_loadri_io;
break;
case MVT::i64:
Opcode = IsValidInc ? Hexagon::L2_loadrd_pi : Hexagon::L2_loadrd_io;
break;
// 64B
case MVT::v64i8:
case MVT::v32i16:
case MVT::v16i32:
case MVT::v8i64:
if (isAlignedMemNode(LD))
Opcode = IsValidInc ? Hexagon::V6_vL32b_pi : Hexagon::V6_vL32b_ai;
else
Opcode = IsZeroExt ? Hexagon::L2_loadruh_io : Hexagon::L2_loadrh_io;
} else if (LoadedVT == MVT::i8) {
if (HII->isValidAutoIncImm(LoadedVT, Val))
Opcode = IsZeroExt ? Hexagon::L2_loadrub_pi : Hexagon::L2_loadrb_pi;
else
Opcode = IsZeroExt ? Hexagon::L2_loadrub_io : Hexagon::L2_loadrb_io;
} else if (LoadedVT == MVT::v16i32 || LoadedVT == MVT::v8i64 ||
LoadedVT == MVT::v32i16 || LoadedVT == MVT::v64i8) {
HasVecOffset = true;
bool Aligned = isAlignedMemNode(LD);
if (HII->isValidAutoIncImm(LoadedVT, Val))
Opcode = Aligned ? Hexagon::V6_vL32b_pi : Hexagon::V6_vL32Ub_pi;
else
Opcode = Aligned ? Hexagon::V6_vL32b_ai : Hexagon::V6_vL32Ub_ai;
Opcode = IsValidInc ? Hexagon::V6_vL32Ub_pi : Hexagon::V6_vL32Ub_ai;
break;
// 128B
} else if (LoadedVT == MVT::v32i32 || LoadedVT == MVT::v16i64 ||
LoadedVT == MVT::v64i16 || LoadedVT == MVT::v128i8) {
if (HST->useHVXOps()) {
bool Aligned = isAlignedMemNode(LD);
HasVecOffset = true;
if (HII->isValidAutoIncImm(LoadedVT, Val))
Opcode = Aligned ? Hexagon::V6_vL32b_pi_128B
: Hexagon::V6_vL32Ub_pi_128B;
case MVT::v128i8:
case MVT::v64i16:
case MVT::v32i32:
case MVT::v16i64:
if (isAlignedMemNode(LD))
Opcode = IsValidInc ? Hexagon::V6_vL32b_pi_128B
: Hexagon::V6_vL32b_ai_128B;
else
Opcode = Aligned ? Hexagon::V6_vL32b_ai_128B
Opcode = IsValidInc ? Hexagon::V6_vL32Ub_pi_128B
: Hexagon::V6_vL32Ub_ai_128B;
}
} else
llvm_unreachable("unknown memory type");
// For zero extended i64 loads, we need to add combine instructions.
if (LD->getValueType(0) == MVT::i64 && IsZeroExt) {
SelectIndexedLoadZeroExtend64(LD, Opcode, dl);
return;
}
// Handle sign extended i64 loads.
if (LD->getValueType(0) == MVT::i64 && ExtType == ISD::SEXTLOAD) {
SelectIndexedLoadSignExtend64(LD, Opcode, dl);
return;
break;
default:
llvm_unreachable("Unexpected memory type in indexed load");
}
if (HII->isValidAutoIncImm(LoadedVT, Val)) {
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, dl, MVT::i32);
SDNode* Result = CurDAG->getMachineNode(Opcode, dl,
LD->getValueType(0),
SDValue IncV = CurDAG->getTargetConstant(Inc, dl, MVT::i32);
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = LD->getMemOperand();
auto getExt64 = [this,ExtType] (MachineSDNode *N, const SDLoc &dl)
-> MachineSDNode* {
if (ExtType == ISD::ZEXTLOAD || ExtType == ISD::EXTLOAD) {
SDValue Zero = CurDAG->getTargetConstant(0, dl, MVT::i32);
return CurDAG->getMachineNode(Hexagon::A4_combineir, dl, MVT::i64,
Zero, SDValue(N, 0));
}
if (ExtType == ISD::SEXTLOAD)
return CurDAG->getMachineNode(Hexagon::A2_sxtw, dl, MVT::i64,
SDValue(N, 0));
return N;
};
// Loaded value Next address Chain
SDValue From[3] = { SDValue(LD,0), SDValue(LD,1), SDValue(LD,2) };
SDValue To[3];
EVT ValueVT = LD->getValueType(0);
if (ValueVT == MVT::i64 && ExtType != ISD::NON_EXTLOAD) {
// A load extending to i64 will actually produce i32, which will then
// need to be extended to i64.
assert(LoadedVT.getSizeInBits() <= 32);
ValueVT = MVT::i32;
}
if (IsValidInc) {
MachineSDNode *L = CurDAG->getMachineNode(Opcode, dl, ValueVT,
MVT::i32, MVT::Other, Base,
TargetConstVal, Chain);
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = LD->getMemOperand();
cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
if (HasVecOffset) {
const SDValue Froms[] = { SDValue(LD, 0),
SDValue(LD, 2)
};
const SDValue Tos[] = { SDValue(Result, 0),
SDValue(Result, 2)
};
ReplaceUses(Froms, Tos, 2);
IncV, Chain);
L->setMemRefs(MemOp, MemOp+1);
To[1] = SDValue(L, 1); // Next address.
To[2] = SDValue(L, 2); // Chain.
// Handle special case for extension to i64.
if (LD->getValueType(0) == MVT::i64)
L = getExt64(L, dl);
To[0] = SDValue(L, 0); // Loaded (extended) value.
} else {
const SDValue Froms[] = { SDValue(LD, 0),
SDValue(LD, 1),
SDValue(LD, 2)
};
const SDValue Tos[] = { SDValue(Result, 0),
SDValue(Result, 1),
SDValue(Result, 2)
};
ReplaceUses(Froms, Tos, 3);
SDValue Zero = CurDAG->getTargetConstant(0, dl, MVT::i32);
MachineSDNode *L = CurDAG->getMachineNode(Opcode, dl, ValueVT, MVT::Other,
Base, Zero, Chain);
L->setMemRefs(MemOp, MemOp+1);
To[2] = SDValue(L, 1); // Chain.
MachineSDNode *A = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
Base, IncV);
To[1] = SDValue(A, 0); // Next address.
// Handle special case for extension to i64.
if (LD->getValueType(0) == MVT::i64)
L = getExt64(L, dl);
To[0] = SDValue(L, 0); // Loaded (extended) value.
}
ReplaceUses(From, To, 3);
CurDAG->RemoveDeadNode(LD);
return;
} else {
SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, dl, MVT::i32);
SDNode* Result_1 = CurDAG->getMachineNode(Opcode, dl,
LD->getValueType(0),
MVT::Other, Base, TargetConst0,
Chain);
SDNode* Result_2 = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
Base, TargetConstVal,
SDValue(Result_1, 1));
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = LD->getMemOperand();
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
const SDValue Froms[] = { SDValue(LD, 0),
SDValue(LD, 1),
SDValue(LD, 2)
};
const SDValue Tos[] = { SDValue(Result_1, 0),
SDValue(Result_2, 0),
SDValue(Result_1, 1)
};
ReplaceUses(Froms, Tos, 3);
CurDAG->RemoveDeadNode(LD);
return;
}
}
@ -644,7 +513,6 @@ bool HexagonDAGToDAGISel::tryLoadOfLoadIntrinsic(LoadSDNode *N) {
return false;
}
void HexagonDAGToDAGISel::SelectLoad(SDNode *N) {
SDLoc dl(N);
LoadSDNode *LD = cast<LoadSDNode>(N);
@ -668,104 +536,89 @@ void HexagonDAGToDAGISel::SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl) {
SDValue Base = ST->getBasePtr();
SDValue Offset = ST->getOffset();
SDValue Value = ST->getValue();
SDNode *OffsetNode = Offset.getNode();
// Get the constant value.
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
int32_t Inc = cast<ConstantSDNode>(Offset.getNode())->getSExtValue();
EVT StoredVT = ST->getMemoryVT();
EVT ValueVT = Value.getValueType();
// Offset value must be within representable range
// and must have correct alignment properties.
if (HII->isValidAutoIncImm(StoredVT, Val)) {
bool IsValidInc = HII->isValidAutoIncImm(StoredVT, Inc);
unsigned Opcode = 0;
// Figure out the post inc version of opcode.
if (StoredVT == MVT::i64) Opcode = Hexagon::S2_storerd_pi;
else if (StoredVT == MVT::i32) Opcode = Hexagon::S2_storeri_pi;
else if (StoredVT == MVT::i16) Opcode = Hexagon::S2_storerh_pi;
else if (StoredVT == MVT::i8) Opcode = Hexagon::S2_storerb_pi;
else if (StoredVT == MVT::v16i32 || StoredVT == MVT::v8i64 ||
StoredVT == MVT::v32i16 || StoredVT == MVT::v64i8) {
assert(StoredVT.isSimple());
switch (StoredVT.getSimpleVT().SimpleTy) {
case MVT::i8:
Opcode = IsValidInc ? Hexagon::S2_storerb_pi : Hexagon::S2_storerb_io;
break;
case MVT::i16:
Opcode = IsValidInc ? Hexagon::S2_storerh_pi : Hexagon::S2_storerh_io;
break;
case MVT::i32:
Opcode = IsValidInc ? Hexagon::S2_storeri_pi : Hexagon::S2_storeri_io;
break;
case MVT::i64:
Opcode = IsValidInc ? Hexagon::S2_storerd_pi : Hexagon::S2_storerd_io;
break;
// 64B
case MVT::v64i8:
case MVT::v32i16:
case MVT::v16i32:
case MVT::v8i64:
if (isAlignedMemNode(ST))
Opcode = Hexagon::V6_vS32b_pi;
Opcode = IsValidInc ? Hexagon::V6_vS32b_pi : Hexagon::V6_vS32b_ai;
else
Opcode = Hexagon::V6_vS32Ub_pi;
}
Opcode = IsValidInc ? Hexagon::V6_vS32Ub_pi : Hexagon::V6_vS32Ub_ai;
break;
// 128B
else if (StoredVT == MVT::v32i32 || StoredVT == MVT::v16i64 ||
StoredVT == MVT::v64i16 || StoredVT == MVT::v128i8) {
if (HST->useHVXOps())
Opcode = isAlignedMemNode(ST) ? Hexagon::V6_vS32b_pi_128B
: Hexagon::V6_vS32Ub_pi_128B;
} else
llvm_unreachable("unknown memory type");
case MVT::v128i8:
case MVT::v64i16:
case MVT::v32i32:
case MVT::v16i64:
if (isAlignedMemNode(ST))
Opcode = IsValidInc ? Hexagon::V6_vS32b_pi_128B
: Hexagon::V6_vS32b_ai_128B;
else
Opcode = IsValidInc ? Hexagon::V6_vS32Ub_pi_128B
: Hexagon::V6_vS32Ub_ai_128B;
break;
default:
llvm_unreachable("Unexpected memory type in indexed store");
}
if (ST->isTruncatingStore() && ValueVT.getSizeInBits() == 64) {
assert(StoredVT.getSizeInBits() < 64 && "Not a truncating store");
Value = CurDAG->getTargetExtractSubreg(Hexagon::subreg_loreg,
dl, MVT::i32, Value);
}
SDValue Ops[] = {Base, CurDAG->getTargetConstant(Val, dl, MVT::i32), Value,
Chain};
SDValue IncV = CurDAG->getTargetConstant(Inc, dl, MVT::i32);
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = ST->getMemOperand();
// Next address Chain
SDValue From[2] = { SDValue(ST,0), SDValue(ST,1) };
SDValue To[2];
if (IsValidInc) {
// Build post increment store.
SDNode* Result = CurDAG->getMachineNode(Opcode, dl, MVT::i32,
MVT::Other, Ops);
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = ST->getMemOperand();
cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
SDValue Ops[] = { Base, IncV, Value, Chain };
MachineSDNode *S = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Other,
Ops);
S->setMemRefs(MemOp, MemOp + 1);
To[0] = SDValue(S, 0);
To[1] = SDValue(S, 1);
} else {
SDValue Zero = CurDAG->getTargetConstant(0, dl, MVT::i32);
SDValue Ops[] = { Base, Zero, Value, Chain };
MachineSDNode *S = CurDAG->getMachineNode(Opcode, dl, MVT::Other, Ops);
S->setMemRefs(MemOp, MemOp + 1);
To[1] = SDValue(S, 0);
MachineSDNode *A = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
Base, IncV);
To[0] = SDValue(A, 0);
}
ReplaceUses(ST, Result);
ReplaceUses(SDValue(ST,1), SDValue(Result,1));
ReplaceUses(From, To, 2);
CurDAG->RemoveDeadNode(ST);
return;
}
// Note: Order of operands matches the def of instruction:
// def S2_storerd_io
// : STInst<(outs), (ins IntRegs:$base, imm:$offset, DoubleRegs:$src1), ...
// and it differs for POST_ST* for instance.
SDValue Ops[] = { Base, CurDAG->getTargetConstant(0, dl, MVT::i32), Value,
Chain};
unsigned Opcode = 0;
// Figure out the opcode.
if (StoredVT == MVT::i64) Opcode = Hexagon::S2_storerd_io;
else if (StoredVT == MVT::i32) Opcode = Hexagon::S2_storeri_io;
else if (StoredVT == MVT::i16) Opcode = Hexagon::S2_storerh_io;
else if (StoredVT == MVT::i8) Opcode = Hexagon::S2_storerb_io;
else if (StoredVT == MVT::v16i32 || StoredVT == MVT::v8i64 ||
StoredVT == MVT::v32i16 || StoredVT == MVT::v64i8) {
if (isAlignedMemNode(ST))
Opcode = Hexagon::V6_vS32b_ai;
else
Opcode = Hexagon::V6_vS32Ub_ai;
}
// 128B
else if (StoredVT == MVT::v32i32 || StoredVT == MVT::v16i64 ||
StoredVT == MVT::v64i16 || StoredVT == MVT::v128i8) {
if (isAlignedMemNode(ST))
Opcode = Hexagon::V6_vS32b_ai_128B;
else
Opcode = Hexagon::V6_vS32Ub_ai_128B;
}
else llvm_unreachable("unknown memory type");
// Build regular store.
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, dl, MVT::i32);
SDNode* Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::Other, Ops);
// Build splitted incriment instruction.
SDNode* Result_2 = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
Base,
TargetConstVal,
SDValue(Result_1, 0));
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = ST->getMemOperand();
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
ReplaceUses(SDValue(ST,0), SDValue(Result_2,0));
ReplaceUses(SDValue(ST,1), SDValue(Result_1,0));
CurDAG->RemoveDeadNode(ST);
return;
}
void HexagonDAGToDAGISel::SelectStore(SDNode *N) {

View File

@ -0,0 +1,52 @@
; RUN: llc -march=hexagon < %s | FileCheck %s
; CHECK: = vmem(r{{[0-9]+}}++#1)
target triple = "hexagon-unknown--elf"
declare <32 x i32> @llvm.hexagon.V6.hi.128B(<64 x i32>) #0
declare <64 x i32> @llvm.hexagon.V6.vcombine.128B(<32 x i32>, <32 x i32>) #0
declare <64 x i32> @llvm.hexagon.V6.vzb.128B(<32 x i32>) #0
declare <32 x i32> @llvm.hexagon.V6.vsathub.128B(<32 x i32>, <32 x i32>) #0
declare <64 x i32> @llvm.hexagon.V6.vaddh.dv.128B(<64 x i32>, <64 x i32>) #0
declare <64 x i32> @llvm.hexagon.V6.vadduhsat.dv.128B(<64 x i32>, <64 x i32>) #0
declare <32 x i32> @llvm.hexagon.V6.vabsdiffuh.128B(<32 x i32>, <32 x i32>) #0
define void @fred() #1 {
entry:
br i1 undef, label %b1, label %call_destructor.exit
b1: ; preds = %entry
br label %b2
b2: ; preds = %b1, %b2
%c2.host32.sroa.3.0 = phi <128 x i8> [ %5, %b2 ], [ undef, %b1 ]
%sobel_halide.s0.x.x = phi i32 [ %17, %b2 ], [ 0, %b1 ]
%0 = add nsw i32 %sobel_halide.s0.x.x, undef
%1 = shl i32 %0, 7
%2 = add nsw i32 %1, 128
%3 = getelementptr inbounds i8, i8* undef, i32 %2
%4 = bitcast i8* %3 to <128 x i8>*
%5 = load <128 x i8>, <128 x i8>* %4, align 128
%6 = bitcast <128 x i8> %c2.host32.sroa.3.0 to <32 x i32>
%7 = tail call <32 x i32> @llvm.hexagon.V6.valignbi.128B(<32 x i32> undef, <32 x i32> %6, i32 1)
%8 = tail call <64 x i32> @llvm.hexagon.V6.vzb.128B(<32 x i32> %7) #1
%9 = tail call <64 x i32> @llvm.hexagon.V6.vadduhsat.dv.128B(<64 x i32> undef, <64 x i32> %8) #1
%10 = tail call <64 x i32> @llvm.hexagon.V6.vadduhsat.dv.128B(<64 x i32> %9, <64 x i32> undef) #1
%11 = tail call <32 x i32> @llvm.hexagon.V6.hi.128B(<64 x i32> %10)
%12 = tail call <32 x i32> @llvm.hexagon.V6.vabsdiffuh.128B(<32 x i32> undef, <32 x i32> %11) #1
%13 = tail call <64 x i32> @llvm.hexagon.V6.vcombine.128B(<32 x i32> %12, <32 x i32> undef)
%14 = tail call <64 x i32> @llvm.hexagon.V6.vaddh.dv.128B(<64 x i32> undef, <64 x i32> %13) #1
%15 = tail call <32 x i32> @llvm.hexagon.V6.hi.128B(<64 x i32> %14) #1
%16 = tail call <32 x i32> @llvm.hexagon.V6.vsathub.128B(<32 x i32> %15, <32 x i32> undef) #1
store <32 x i32> %16, <32 x i32>* undef, align 128
%17 = add nuw nsw i32 %sobel_halide.s0.x.x, 1
br label %b2
call_destructor.exit: ; preds = %entry
ret void
}
declare <32 x i32> @llvm.hexagon.V6.valignbi.128B(<32 x i32>, <32 x i32>, i32) #0
attributes #0 = { nounwind readnone }
attributes #1 = { nounwind "target-cpu"="hexagonv60" "target-features"="+hvx,+hvx-double" }