mirror of
https://github.com/RPCSX/llvm.git
synced 2025-04-03 16:51:42 +00:00
[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:
parent
cb2753f32e
commit
99719f40ee
@ -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) {
|
||||
|
52
test/CodeGen/Hexagon/vload-postinc-sel.ll
Normal file
52
test/CodeGen/Hexagon/vload-postinc-sel.ll
Normal 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" }
|
Loading…
x
Reference in New Issue
Block a user