mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-24 15:00:45 +02:00
Merge pull request #9 from Sonicadvance1/unittests/stos
Adds unit tests for the STOS instruction family
This commit is contained in:
commit
e2e9e1eb41
13 files changed
+483
-46
No files matched your search
+73
-46
@@ -1748,71 +1748,98 @@ void OpDispatchBuilder::DECOp(OpcodeArgs) {
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::STOSOp(OpcodeArgs) {
|
||||
LogMan::Throw::A(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX, "Can't handle REP not existing on STOS\n");
|
||||
LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "Invalid REPNE on STOS");
|
||||
|
||||
auto Size = GetSrcSize(Op);
|
||||
|
||||
// Create all our blocks
|
||||
auto LoopHead = CreateNewCodeBlock();
|
||||
auto LoopTail = CreateNewCodeBlock();
|
||||
auto LoopEnd = CreateNewCodeBlock();
|
||||
|
||||
// At the time this was written, our RA can't handle accessing nodes across blocks.
|
||||
// So we need to re-load and re-calculate essential values each iteration of the loop.
|
||||
bool Repeat = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX;
|
||||
|
||||
// First thing we need to do is finish this block and jump to the start of the loop.
|
||||
_Jump(LoopHead);
|
||||
if (!Repeat) {
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
OrderedNode *Dest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
|
||||
SetCurrentCodeBlock(LoopHead);
|
||||
{
|
||||
OrderedNode *Counter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass);
|
||||
auto ZeroConst = _Constant(0);
|
||||
// Store to memory where RDI points
|
||||
_StoreMem(GPRClass, Size, Dest, Src, Size);
|
||||
|
||||
// Can we end the block?
|
||||
auto CanLeaveCond = _Select(FEXCore::IR::COND_EQ,
|
||||
Counter, ZeroConst,
|
||||
_Constant(1), ZeroConst);
|
||||
auto SizeConst = _Constant(Size);
|
||||
auto NegSizeConst = _Constant(-Size);
|
||||
|
||||
_CondJump(CanLeaveCond, LoopEnd, LoopTail);
|
||||
}
|
||||
// Calculate direction.
|
||||
auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC);
|
||||
auto PtrDir = _Select(FEXCore::IR::COND_EQ,
|
||||
DF, _Constant(0),
|
||||
SizeConst, NegSizeConst);
|
||||
|
||||
SetCurrentCodeBlock(LoopTail);
|
||||
{
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
OrderedNode *Dest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
// Offset the pointer
|
||||
OrderedNode *TailDest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
TailDest = _Add(TailDest, PtrDir);
|
||||
_StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), TailDest);
|
||||
|
||||
// Store to memory where RDI points
|
||||
_StoreMem(GPRClass, Size, Dest, Src, Size);
|
||||
}
|
||||
else {
|
||||
// Create all our blocks
|
||||
auto LoopHead = CreateNewCodeBlock();
|
||||
auto LoopTail = CreateNewCodeBlock();
|
||||
auto LoopEnd = CreateNewCodeBlock();
|
||||
|
||||
OrderedNode *TailCounter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass);
|
||||
OrderedNode *TailDest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
// At the time this was written, our RA can't handle accessing nodes across blocks.
|
||||
// So we need to re-load and re-calculate essential values each iteration of the loop.
|
||||
|
||||
// Decrement counter
|
||||
TailCounter = _Sub(TailCounter, _Constant(1));
|
||||
// First thing we need to do is finish this block and jump to the start of the loop.
|
||||
_Jump(LoopHead);
|
||||
|
||||
// Store the counter so we don't have to deal with PHI here
|
||||
_StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), TailCounter);
|
||||
SetCurrentCodeBlock(LoopHead);
|
||||
{
|
||||
OrderedNode *Counter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass);
|
||||
auto ZeroConst = _Constant(0);
|
||||
|
||||
auto SizeConst = _Constant(Size);
|
||||
auto NegSizeConst = _Constant(-Size);
|
||||
// Can we end the block?
|
||||
auto CanLeaveCond = _Select(FEXCore::IR::COND_EQ,
|
||||
Counter, ZeroConst,
|
||||
_Constant(1), ZeroConst);
|
||||
|
||||
// Calculate direction.
|
||||
auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC);
|
||||
auto PtrDir = _Select(FEXCore::IR::COND_EQ,
|
||||
DF, _Constant(0),
|
||||
SizeConst, NegSizeConst);
|
||||
_CondJump(CanLeaveCond, LoopEnd, LoopTail);
|
||||
}
|
||||
|
||||
// Offset the pointer
|
||||
TailDest = _Add(TailDest, PtrDir);
|
||||
_StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), TailDest);
|
||||
SetCurrentCodeBlock(LoopTail);
|
||||
{
|
||||
OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
OrderedNode *Dest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
|
||||
// Jump back to the start, we have more work to do
|
||||
_Jump(LoopHead);
|
||||
}
|
||||
// Store to memory where RDI points
|
||||
_StoreMem(GPRClass, Size, Dest, Src, Size);
|
||||
|
||||
// Make sure to start a new block after ending this one
|
||||
OrderedNode *TailCounter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass);
|
||||
OrderedNode *TailDest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass);
|
||||
|
||||
SetCurrentCodeBlock(LoopEnd);
|
||||
// Decrement counter
|
||||
TailCounter = _Sub(TailCounter, _Constant(1));
|
||||
|
||||
// Store the counter so we don't have to deal with PHI here
|
||||
_StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), TailCounter);
|
||||
|
||||
auto SizeConst = _Constant(Size);
|
||||
auto NegSizeConst = _Constant(-Size);
|
||||
|
||||
// Calculate direction.
|
||||
auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC);
|
||||
auto PtrDir = _Select(FEXCore::IR::COND_EQ,
|
||||
DF, _Constant(0),
|
||||
SizeConst, NegSizeConst);
|
||||
|
||||
// Offset the pointer
|
||||
TailDest = _Add(TailDest, PtrDir);
|
||||
_StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), TailDest);
|
||||
|
||||
// Jump back to the start, we have more work to do
|
||||
_Jump(LoopHead);
|
||||
}
|
||||
|
||||
// Make sure to start a new block after ending this one
|
||||
|
||||
SetCurrentCodeBlock(LoopEnd);
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::MOVSOp(OpcodeArgs) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF2F2F2F2F2F2F2F2",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE0000018"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rax, 0xF2
|
||||
stosb ; rdi <- al
|
||||
stosb
|
||||
stosb
|
||||
stosb
|
||||
|
||||
stosb
|
||||
stosb
|
||||
stosb
|
||||
stosb
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF2F2F2F2F2F2F2F2",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE0000018"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rcx, 8
|
||||
mov rax, 0xF2
|
||||
rep stosb ; rdi <- rsi
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF2F2F2F2F2F2F2F2",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE000000F"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2 + 7]
|
||||
|
||||
std
|
||||
mov rcx, 8
|
||||
mov rax, 0xF2
|
||||
rep stosb ; rdi <- rsi
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F3F4F1F2F3F4",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE0000018"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rax, 0xF1F2F3F4
|
||||
stosd ; rdi <- eax
|
||||
stosd
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F3F4F1F2F3F4",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE0000018"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rax, 0xF1F2F3F4
|
||||
mov rcx, 2
|
||||
rep stosd ; rdi <- eax
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F3F4F1F2F3F4",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE000000C"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2 + 4]
|
||||
|
||||
std
|
||||
mov rax, 0xF1F2F3F4
|
||||
mov rcx, 2
|
||||
rep stosd ; rdi <- eax
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,32 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F3F4F5F6F7F8",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE0000018"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rax, 0xF1F2F3F4F5F6F7F8
|
||||
stosq ; rdi <- rax
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,36 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F3F4F5F6F7F8",
|
||||
"RDX": "0xF1F2F3F4F5F6F7F8",
|
||||
"RSI": "0x0",
|
||||
"RDI": "0xE0000020"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
mov [rdx + 8 * 4], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rax, 0xF1F2F3F4F5F6F7F8
|
||||
mov rcx, 2
|
||||
rep stosq ; rdi <- rax
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rsi, [rdx + 8 * 4]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,36 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F3F4F5F6F7F8",
|
||||
"RDX": "0xF1F2F3F4F5F6F7F8",
|
||||
"RSI": "0x0",
|
||||
"RDI": "0xE0000008"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
mov [rdx + 8 * 4], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 3]
|
||||
|
||||
std
|
||||
mov rax, 0xF1F2F3F4F5F6F7F8
|
||||
mov rcx, 2
|
||||
rep stosq ; rdi <- rax
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rsi, [rdx + 8 * 4]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,35 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F1F2F1F2F1F2",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE0000018"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rax, 0xF1F2
|
||||
stosw ; rdi <- ax
|
||||
stosw
|
||||
stosw
|
||||
stosw
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F1F2F1F2F1F2",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE0000018"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2]
|
||||
|
||||
cld
|
||||
mov rcx, 0x4
|
||||
mov rax, 0xF1F2
|
||||
rep stosw ; rdi <- ax
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
@@ -0,0 +1,33 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xF1F2F1F2F1F2F1F2",
|
||||
"RDX": "0x0",
|
||||
"RDI": "0xE000000E"
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
mov rdx, 0xe0000000
|
||||
|
||||
mov rax, 0x4142434445464748
|
||||
mov [rdx + 8 * 0], rax
|
||||
mov rax, 0x5152535455565758
|
||||
mov [rdx + 8 * 1], rax
|
||||
mov rax, 0x0
|
||||
mov [rdx + 8 * 2], rax
|
||||
mov [rdx + 8 * 3], rax
|
||||
|
||||
lea rdi, [rdx + 8 * 2 + 6]
|
||||
|
||||
std
|
||||
mov rcx, 0x4
|
||||
mov rax, 0xF1F2
|
||||
rep stosw ; rdi <- ax
|
||||
|
||||
mov rax, [rdx + 8 * 2]
|
||||
mov rdx, [rdx + 8 * 3]
|
||||
hlt
|
||||
Reference in new issue
Block a user