Skip to content

Commit

Permalink
Merge pull request #3281 from Sonicadvance1/optimize_constantdirectio…
Browse files Browse the repository at this point in the history
…n_memsetcpy

FEXCore: Optimize memcpy and memset when direction is compile time constant
  • Loading branch information
alyssarosenzweig committed Nov 28, 2023
2 parents 8e892ec + 27f3cb3 commit 85a1c1f
Show file tree
Hide file tree
Showing 3 changed files with 522 additions and 22 deletions.
77 changes: 55 additions & 22 deletions FEXCore/Source/Interface/Core/JIT/Arm64/MemoryOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1863,9 +1863,15 @@ DEF_OP(MemSet) {
const auto MemReg = GetReg(Op->Addr.ID());
const auto Value = GetReg(Op->Value.ID());
const auto Length = GetReg(Op->Length.ID());
const auto Direction = GetReg(Op->Direction.ID());
const auto Dst = GetReg(Node);

uint64_t DirectionConstant;
bool DirectionIsInline = IsInlineConstant(Op->Direction, &DirectionConstant);
FEXCore::ARMEmitter::Register DirectionReg = ARMEmitter::Reg::r0;
if (!DirectionIsInline) {
DirectionReg = GetReg(Op->Direction.ID());
}

// If Direction == 0 then:
// MemReg is incremented (by size)
// else:
Expand All @@ -1885,8 +1891,10 @@ DEF_OP(MemSet) {
add(TMP2, Prefix.X(), MemReg.X());
}

// Backward or forwards implementation depends on flag
cbnz(ARMEmitter::Size::i64Bit, Direction, &BackwardImpl);
if (!DirectionIsInline) {
// Backward or forwards implementation depends on flag
cbnz(ARMEmitter::Size::i64Bit, DirectionReg, &BackwardImpl);
}

auto MemStore = [this](auto Value, uint32_t OpSize, int32_t Size) {
switch (OpSize) {
Expand Down Expand Up @@ -1940,8 +1948,7 @@ DEF_OP(MemSet) {
}
};

// Emit forward direction memset then backward direction memset.
for (int32_t Direction : { 1, -1 }) {
auto EmitMemset = [&](int32_t Direction) {
const int32_t OpSize = Size;
const int32_t SizeDirection = Size * Direction;

Expand Down Expand Up @@ -2001,15 +2008,26 @@ DEF_OP(MemSet) {
break;
}
}
};

if (Direction == 1) {
b(&Done);
Bind(&BackwardImpl);
}
if (DirectionIsInline) {
// If the direction constant is set then the direction is negative.
EmitMemset(DirectionConstant ? -1 : 1);
}
else {
// Emit forward direction memset then backward direction memset.
for (int32_t Direction : { 1, -1 }) {
EmitMemset(Direction);

if (Direction == 1) {
b(&Done);
Bind(&BackwardImpl);
}
}

Bind(&Done);
// Destination already set to the final pointer.
Bind(&Done);
// Destination already set to the final pointer.
}
}

DEF_OP(MemCpy) {
Expand All @@ -2024,7 +2042,12 @@ DEF_OP(MemCpy) {
const auto MemRegSrc = GetReg(Op->AddrSrc.ID());

const auto Length = GetReg(Op->Length.ID());
const auto Direction = GetReg(Op->Direction.ID());
uint64_t DirectionConstant;
bool DirectionIsInline = IsInlineConstant(Op->Direction, &DirectionConstant);
FEXCore::ARMEmitter::Register DirectionReg = ARMEmitter::Reg::r0;
if (!DirectionIsInline) {
DirectionReg = GetReg(Op->Direction.ID());
}

auto Dst = GetRegPair(Node);
// If Direction == 0 then:
Expand Down Expand Up @@ -2061,8 +2084,10 @@ DEF_OP(MemCpy) {
// TMP3 = Src
// TMP4 = load+store temp value

// Backward or forwards implementation depends on flag
cbnz(ARMEmitter::Size::i64Bit, Direction, &BackwardImpl);
if (!DirectionIsInline) {
// Backward or forwards implementation depends on flag
cbnz(ARMEmitter::Size::i64Bit, DirectionReg, &BackwardImpl);
}

auto MemCpy = [this](uint32_t OpSize, int32_t Size) {
switch (OpSize) {
Expand Down Expand Up @@ -2184,8 +2209,7 @@ DEF_OP(MemCpy) {
}
};

// Emit forward direction memset then backward direction memset.
for (int32_t Direction : { 1, -1 }) {
auto EmitMemcpy = [&](int32_t Direction) {
const int32_t OpSize = Size;
const int32_t SizeDirection = Size * Direction;

Expand Down Expand Up @@ -2258,15 +2282,24 @@ DEF_OP(MemCpy) {
break;
}
}
};

if (Direction == 1) {
b(&Done);
Bind(&BackwardImpl);
if (DirectionIsInline) {
// If the direction constant is set then the direction is negative.
EmitMemcpy(DirectionConstant ? -1 : 1);
}
else {
// Emit forward direction memset then backward direction memset.
for (int32_t Direction : { 1, -1 }) {
EmitMemcpy(Direction);
if (Direction == 1) {
b(&Done);
Bind(&BackwardImpl);
}
}
Bind(&Done);
// Destination already set to the final pointer.
}

Bind(&Done);
// Destination already set to the final pointer.
}

DEF_OP(ParanoidLoadMemTSO) {
Expand Down
29 changes: 29 additions & 0 deletions FEXCore/Source/Interface/IR/Passes/ConstProp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,35 @@ bool ConstProp::ConstantInlining(IREmitter *IREmit, const IRListView& CurrentIR)
}
break;
}
case OP_MEMCPY:
{
auto Op = IROp->CW<IR::IROp_MemCpy>();

uint64_t Constant{};
if (IREmit->IsValueConstant(Op->Direction, &Constant)) {
IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Direction));

IREmit->ReplaceNodeArgument(CodeNode, Op->Direction_Index, CreateInlineConstant(IREmit, Constant & 1));

Changed = true;
}
break;
}
case OP_MEMSET:
{
auto Op = IROp->CW<IR::IROp_MemSet>();

uint64_t Constant{};
if (IREmit->IsValueConstant(Op->Direction, &Constant)) {
IREmit->SetWriteCursor(CurrentIR.GetNode(Op->Direction));

IREmit->ReplaceNodeArgument(CodeNode, Op->Direction_Index, CreateInlineConstant(IREmit, Constant & 1));

Changed = true;
}
break;
}

default:
break;
}
Expand Down

0 comments on commit 85a1c1f

Please sign in to comment.