Fixing some particularly bad /W4.
This commit is contained in:
@@ -212,8 +212,7 @@ struct ValueOp : Op<ValueOp<T, KEY_TYPE, REG_TYPE, CONST_TYPE>, KEY_TYPE> {
|
||||
bool operator==(const Xbyak::Reg& b) const { return IsEqual(b); }
|
||||
bool operator!=(const Xbyak::Reg& b) const { return !IsEqual(b); }
|
||||
void Load(const Instr::Op& op) {
|
||||
const Value* value = op.value;
|
||||
this->value = value;
|
||||
value = op.value;
|
||||
is_constant = value->IsConstant();
|
||||
if (!is_constant) {
|
||||
X64Emitter::SetupReg(value, reg_);
|
||||
|
||||
@@ -55,7 +55,7 @@ bool DataFlowAnalysisPass::Run(HIRBuilder* builder) {
|
||||
uint32_t DataFlowAnalysisPass::LinearizeBlocks(HIRBuilder* builder) {
|
||||
// TODO(benvanik): actually do this - we cheat now knowing that they are in
|
||||
// sequential order.
|
||||
uint32_t block_ordinal = 0;
|
||||
uint16_t block_ordinal = 0;
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
block->ordinal = block_ordinal++;
|
||||
|
||||
@@ -34,7 +34,7 @@ bool FinalizationPass::Run(HIRBuilder* builder) {
|
||||
|
||||
auto arena = builder->arena();
|
||||
|
||||
uint32_t block_ordinal = 0;
|
||||
uint16_t block_ordinal = 0;
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
block->ordinal = block_ordinal++;
|
||||
|
||||
@@ -77,7 +77,7 @@ bool RegisterAllocationPass::Run(HIRBuilder* builder) {
|
||||
// Really, it'd just be nice to have someone who knew what they
|
||||
// were doing lower SSA and do this right.
|
||||
|
||||
uint32_t block_ordinal = 0;
|
||||
uint16_t block_ordinal = 0;
|
||||
uint32_t instr_ordinal = 0;
|
||||
auto block = builder->first_block();
|
||||
while (block) {
|
||||
@@ -212,27 +212,27 @@ void RegisterAllocationPass::AdvanceUses(Instr* instr) {
|
||||
break;
|
||||
}
|
||||
auto& upcoming_uses = usage_set->upcoming_uses;
|
||||
for (int i = 0; i < upcoming_uses.size();) {
|
||||
auto& upcoming_use = upcoming_uses.at(i);
|
||||
for (size_t j = 0; j < upcoming_uses.size();) {
|
||||
auto& upcoming_use = upcoming_uses.at(j);
|
||||
if (!upcoming_use.use) {
|
||||
// No uses at all - we can remove right away.
|
||||
// This comes up from instructions where the dest is never used,
|
||||
// like the ATOMIC ops.
|
||||
MarkRegAvailable(upcoming_use.value->reg);
|
||||
upcoming_uses.erase(upcoming_uses.begin() + i);
|
||||
upcoming_uses.erase(upcoming_uses.begin() + j);
|
||||
// i remains the same.
|
||||
continue;
|
||||
}
|
||||
if (upcoming_use.use->instr != instr) {
|
||||
// Not yet at this instruction.
|
||||
++i;
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
// The use is from this instruction.
|
||||
if (!upcoming_use.use->next) {
|
||||
// Last use of the value. We can retire it now.
|
||||
MarkRegAvailable(upcoming_use.value->reg);
|
||||
upcoming_uses.erase(upcoming_uses.begin() + i);
|
||||
upcoming_uses.erase(upcoming_uses.begin() + j);
|
||||
// i remains the same.
|
||||
continue;
|
||||
} else {
|
||||
@@ -245,7 +245,7 @@ void RegisterAllocationPass::AdvanceUses(Instr* instr) {
|
||||
}
|
||||
// Remove the iterator.
|
||||
auto value = upcoming_use.value;
|
||||
upcoming_uses.erase(upcoming_uses.begin() + i);
|
||||
upcoming_uses.erase(upcoming_uses.begin() + j);
|
||||
assert_true(next_use->instr->block == instr->block);
|
||||
assert_true(value->def->block == instr->block);
|
||||
upcoming_uses.emplace_back(value, next_use);
|
||||
|
||||
@@ -23,30 +23,30 @@ struct ExportTag {
|
||||
typedef uint32_t type;
|
||||
|
||||
// Export is implemented in some form and can be used.
|
||||
static const type kImplemented = 1 << 0;
|
||||
static const type kImplemented = 1u << 0;
|
||||
// Export is a stub and is probably bad.
|
||||
static const type kStub = 1 << 1;
|
||||
static const type kStub = 1u << 1;
|
||||
// Export is known to cause problems, or may not be complete.
|
||||
static const type kSketchy = 1 << 2;
|
||||
static const type kSketchy = 1u << 2;
|
||||
// Export is called *a lot*.
|
||||
static const type kHighFrequency = 1 << 3;
|
||||
static const type kHighFrequency = 1u << 3;
|
||||
// Export is important and should always be logged.
|
||||
static const type kImportant = 1 << 4;
|
||||
static const type kImportant = 1u << 4;
|
||||
|
||||
static const type kThreading = 1 << 10;
|
||||
static const type kInput = 1 << 11;
|
||||
static const type kAudio = 1 << 12;
|
||||
static const type kVideo = 1 << 13;
|
||||
static const type kFileSystem = 1 << 14;
|
||||
static const type kModules = 1 << 15;
|
||||
static const type kUserProfiles = 1 << 16;
|
||||
static const type kNetworking = 1 << 17;
|
||||
static const type kMemory = 1 << 18;
|
||||
static const type kThreading = 1u << 10;
|
||||
static const type kInput = 1u << 11;
|
||||
static const type kAudio = 1u << 12;
|
||||
static const type kVideo = 1u << 13;
|
||||
static const type kFileSystem = 1u << 14;
|
||||
static const type kModules = 1u << 15;
|
||||
static const type kUserProfiles = 1u << 16;
|
||||
static const type kNetworking = 1u << 17;
|
||||
static const type kMemory = 1u << 18;
|
||||
|
||||
// Export will be logged on each call.
|
||||
static const type kLog = 1 << 30;
|
||||
static const type kLog = 1u << 30;
|
||||
// Export's result will be logged on each call.
|
||||
static const type kLogResult = 1 << 31;
|
||||
static const type kLogResult = 1u << 31;
|
||||
};
|
||||
|
||||
// DEPRECATED
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace frontend {
|
||||
// 100: invalid
|
||||
// 128-256: VR
|
||||
|
||||
#pragma pack(push, 4)
|
||||
#pragma pack(push, 8)
|
||||
typedef struct alignas(64) PPCContext_s {
|
||||
// Must be stored at 0x0 for now.
|
||||
// TODO(benvanik): find a nice way to describe this to the JIT.
|
||||
@@ -49,9 +49,11 @@ typedef struct alignas(64) PPCContext_s {
|
||||
uint8_t* virtual_membase;
|
||||
|
||||
// Most frequently used registers first.
|
||||
uint64_t r[32]; // General purpose registers
|
||||
uint64_t lr; // Link register
|
||||
uint64_t ctr; // Count register
|
||||
uint64_t lr; // Link register
|
||||
uint64_t ctr; // Count register
|
||||
uint64_t r[32]; // General purpose registers
|
||||
double f[32]; // Floating-point registers
|
||||
vec128_t v[128]; // VMX128 vector registers
|
||||
|
||||
// XER register
|
||||
// Split to make it easier to do individual updates.
|
||||
@@ -188,9 +190,6 @@ typedef struct alignas(64) PPCContext_s {
|
||||
|
||||
uint8_t vscr_sat;
|
||||
|
||||
double f[32]; // Floating-point registers
|
||||
vec128_t v[128]; // VMX128 vector registers
|
||||
|
||||
// uint32_t get_fprf() {
|
||||
// return fpscr.value & 0x000F8000;
|
||||
// }
|
||||
@@ -216,11 +215,15 @@ typedef struct alignas(64) PPCContext_s {
|
||||
|
||||
uint8_t* physical_membase;
|
||||
|
||||
// Keep the struct padded out to 64b total.
|
||||
uint8_t _padding[8];
|
||||
|
||||
void SetRegFromString(const char* name, const char* value);
|
||||
bool CompareRegWithString(const char* name, const char* value,
|
||||
char* out_value, size_t out_value_size);
|
||||
} PPCContext;
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(PPCContext) % 64 == 0, "64b padded");
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace cpu
|
||||
|
||||
@@ -295,10 +295,11 @@ void InstrAccessBits::Dump(std::string& out_str) {
|
||||
out_str = str.str();
|
||||
}
|
||||
|
||||
void InstrDisasm::Init(const char* name, const char* info, uint32_t flags) {
|
||||
this->name = name;
|
||||
this->info = info;
|
||||
this->flags = flags;
|
||||
void InstrDisasm::Init(const char* new_name, const char* new_info,
|
||||
uint32_t new_flags) {
|
||||
name = new_name;
|
||||
info = new_info;
|
||||
flags = new_flags;
|
||||
}
|
||||
|
||||
void InstrDisasm::AddLR(InstrRegister::Access access) {}
|
||||
|
||||
@@ -483,7 +483,7 @@ class InstrDisasm {
|
||||
const char* info;
|
||||
uint32_t flags;
|
||||
|
||||
void Init(const char* name, const char* info, uint32_t flags);
|
||||
void Init(const char* new_name, const char* new_info, uint32_t new_flags);
|
||||
void AddLR(InstrRegister::Access access);
|
||||
void AddCTR(InstrRegister::Access access);
|
||||
void AddCR(uint32_t bf, InstrRegister::Access access);
|
||||
|
||||
@@ -388,7 +388,7 @@ void HIRBuilder::InsertLabel(Label* label, Instr* prev_instr) {
|
||||
Block* next_block = prev_instr->block->next;
|
||||
|
||||
Block* new_block = arena_->Alloc<Block>();
|
||||
new_block->ordinal = -1;
|
||||
new_block->ordinal = UINT16_MAX;
|
||||
new_block->incoming_values = nullptr;
|
||||
new_block->arena = arena_;
|
||||
new_block->prev = prev_block;
|
||||
@@ -466,10 +466,10 @@ void HIRBuilder::AddEdge(Block* src, Block* dest, uint32_t flags) {
|
||||
|
||||
if (dest_was_dominated) {
|
||||
// If dest was previously dominated it no longer is.
|
||||
auto edge = dest->incoming_edge_head;
|
||||
while (edge) {
|
||||
edge->flags &= ~Edge::DOMINATES;
|
||||
edge = edge->incoming_next;
|
||||
auto incoming_edge = dest->incoming_edge_head;
|
||||
while (incoming_edge) {
|
||||
incoming_edge->flags &= ~Edge::DOMINATES;
|
||||
incoming_edge = incoming_edge->incoming_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,7 +633,7 @@ void HIRBuilder::MergeAdjacentBlocks(Block* left, Block* right) {
|
||||
|
||||
Block* HIRBuilder::AppendBlock() {
|
||||
Block* block = arena_->Alloc<Block>();
|
||||
block->ordinal = -1;
|
||||
block->ordinal = UINT16_MAX;
|
||||
block->incoming_values = nullptr;
|
||||
block->arena = arena_;
|
||||
block->next = NULL;
|
||||
@@ -690,7 +690,7 @@ Instr* HIRBuilder::AppendInstr(const OpcodeInfo& opcode_info, uint16_t flags,
|
||||
if (!block->instr_head) {
|
||||
block->instr_head = instr;
|
||||
}
|
||||
instr->ordinal = -1;
|
||||
instr->ordinal = UINT32_MAX;
|
||||
instr->block = block;
|
||||
instr->opcode = &opcode_info;
|
||||
instr->flags = flags;
|
||||
@@ -824,7 +824,7 @@ void HIRBuilder::TrapTrue(Value* cond, uint16_t trap_code) {
|
||||
EndBlock();
|
||||
}
|
||||
|
||||
void HIRBuilder::Call(FunctionInfo* symbol_info, uint32_t call_flags) {
|
||||
void HIRBuilder::Call(FunctionInfo* symbol_info, uint16_t call_flags) {
|
||||
Instr* i = AppendInstr(OPCODE_CALL_info, call_flags);
|
||||
i->src1.symbol_info = symbol_info;
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
@@ -832,7 +832,7 @@ void HIRBuilder::Call(FunctionInfo* symbol_info, uint32_t call_flags) {
|
||||
}
|
||||
|
||||
void HIRBuilder::CallTrue(Value* cond, FunctionInfo* symbol_info,
|
||||
uint32_t call_flags) {
|
||||
uint16_t call_flags) {
|
||||
if (cond->IsConstant()) {
|
||||
if (cond->IsConstantTrue()) {
|
||||
Call(symbol_info, call_flags);
|
||||
@@ -847,7 +847,7 @@ void HIRBuilder::CallTrue(Value* cond, FunctionInfo* symbol_info,
|
||||
EndBlock();
|
||||
}
|
||||
|
||||
void HIRBuilder::CallIndirect(Value* value, uint32_t call_flags) {
|
||||
void HIRBuilder::CallIndirect(Value* value, uint16_t call_flags) {
|
||||
ASSERT_CALL_ADDRESS_TYPE(value);
|
||||
Instr* i = AppendInstr(OPCODE_CALL_INDIRECT_info, call_flags);
|
||||
i->set_src1(value);
|
||||
@@ -856,7 +856,7 @@ void HIRBuilder::CallIndirect(Value* value, uint32_t call_flags) {
|
||||
}
|
||||
|
||||
void HIRBuilder::CallIndirectTrue(Value* cond, Value* value,
|
||||
uint32_t call_flags) {
|
||||
uint16_t call_flags) {
|
||||
if (cond->IsConstant()) {
|
||||
if (cond->IsConstantTrue()) {
|
||||
CallIndirect(value, call_flags);
|
||||
@@ -907,14 +907,14 @@ void HIRBuilder::SetReturnAddress(Value* value) {
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
}
|
||||
|
||||
void HIRBuilder::Branch(Label* label, uint32_t branch_flags) {
|
||||
void HIRBuilder::Branch(Label* label, uint16_t branch_flags) {
|
||||
Instr* i = AppendInstr(OPCODE_BRANCH_info, branch_flags);
|
||||
i->src1.label = label;
|
||||
i->src2.value = i->src3.value = NULL;
|
||||
EndBlock();
|
||||
}
|
||||
|
||||
void HIRBuilder::Branch(Block* block, uint32_t branch_flags) {
|
||||
void HIRBuilder::Branch(Block* block, uint16_t branch_flags) {
|
||||
if (!block->label_head) {
|
||||
// Block needs a label.
|
||||
Label* label = NewLabel();
|
||||
@@ -923,7 +923,7 @@ void HIRBuilder::Branch(Block* block, uint32_t branch_flags) {
|
||||
Branch(block->label_head, branch_flags);
|
||||
}
|
||||
|
||||
void HIRBuilder::BranchTrue(Value* cond, Label* label, uint32_t branch_flags) {
|
||||
void HIRBuilder::BranchTrue(Value* cond, Label* label, uint16_t branch_flags) {
|
||||
if (cond->IsConstant()) {
|
||||
if (cond->IsConstantTrue()) {
|
||||
Branch(label, branch_flags);
|
||||
@@ -938,7 +938,7 @@ void HIRBuilder::BranchTrue(Value* cond, Label* label, uint32_t branch_flags) {
|
||||
EndBlock();
|
||||
}
|
||||
|
||||
void HIRBuilder::BranchFalse(Value* cond, Label* label, uint32_t branch_flags) {
|
||||
void HIRBuilder::BranchFalse(Value* cond, Label* label, uint16_t branch_flags) {
|
||||
if (cond->IsConstant()) {
|
||||
if (cond->IsConstantFalse()) {
|
||||
Branch(label, branch_flags);
|
||||
|
||||
@@ -83,20 +83,20 @@ class HIRBuilder {
|
||||
void Trap(uint16_t trap_code = 0);
|
||||
void TrapTrue(Value* cond, uint16_t trap_code = 0);
|
||||
|
||||
void Call(FunctionInfo* symbol_info, uint32_t call_flags = 0);
|
||||
void Call(FunctionInfo* symbol_info, uint16_t call_flags = 0);
|
||||
void CallTrue(Value* cond, FunctionInfo* symbol_info,
|
||||
uint32_t call_flags = 0);
|
||||
void CallIndirect(Value* value, uint32_t call_flags = 0);
|
||||
void CallIndirectTrue(Value* cond, Value* value, uint32_t call_flags = 0);
|
||||
uint16_t call_flags = 0);
|
||||
void CallIndirect(Value* value, uint16_t call_flags = 0);
|
||||
void CallIndirectTrue(Value* cond, Value* value, uint16_t call_flags = 0);
|
||||
void CallExtern(FunctionInfo* symbol_info);
|
||||
void Return();
|
||||
void ReturnTrue(Value* cond);
|
||||
void SetReturnAddress(Value* value);
|
||||
|
||||
void Branch(Label* label, uint32_t branch_flags = 0);
|
||||
void Branch(Block* block, uint32_t branch_flags = 0);
|
||||
void BranchTrue(Value* cond, Label* label, uint32_t branch_flags = 0);
|
||||
void BranchFalse(Value* cond, Label* label, uint32_t branch_flags = 0);
|
||||
void Branch(Label* label, uint16_t branch_flags = 0);
|
||||
void Branch(Block* block, uint16_t branch_flags = 0);
|
||||
void BranchTrue(Value* cond, Label* label, uint16_t branch_flags = 0);
|
||||
void BranchFalse(Value* cond, Label* label, uint16_t branch_flags = 0);
|
||||
|
||||
// phi type_name, Block* b1, Value* v1, Block* b2, Value* v2, etc
|
||||
|
||||
|
||||
@@ -78,9 +78,9 @@ void Instr::MoveBefore(Instr* other) {
|
||||
}
|
||||
}
|
||||
|
||||
void Instr::Replace(const OpcodeInfo* opcode, uint16_t flags) {
|
||||
this->opcode = opcode;
|
||||
this->flags = flags;
|
||||
void Instr::Replace(const OpcodeInfo* new_opcode, uint16_t new_flags) {
|
||||
opcode = new_opcode;
|
||||
flags = new_flags;
|
||||
|
||||
if (src1_use) {
|
||||
src1.value->RemoveUse(src1_use);
|
||||
|
||||
@@ -57,7 +57,7 @@ class Instr {
|
||||
void set_src3(Value* value);
|
||||
|
||||
void MoveBefore(Instr* other);
|
||||
void Replace(const OpcodeInfo* opcode, uint16_t flags);
|
||||
void Replace(const OpcodeInfo* new_opcode, uint16_t new_flags);
|
||||
void Remove();
|
||||
};
|
||||
|
||||
|
||||
@@ -421,22 +421,22 @@ void Value::Neg() {
|
||||
void Value::Abs() {
|
||||
switch (type) {
|
||||
case INT8_TYPE:
|
||||
constant.i8 = abs(constant.i8);
|
||||
constant.i8 = int8_t(std::abs(constant.i8));
|
||||
break;
|
||||
case INT16_TYPE:
|
||||
constant.i16 = abs(constant.i16);
|
||||
constant.i16 = int16_t(std::abs(constant.i16));
|
||||
break;
|
||||
case INT32_TYPE:
|
||||
constant.i32 = abs(constant.i32);
|
||||
constant.i32 = std::abs(constant.i32);
|
||||
break;
|
||||
case INT64_TYPE:
|
||||
constant.i64 = abs(constant.i64);
|
||||
constant.i64 = std::abs(constant.i64);
|
||||
break;
|
||||
case FLOAT32_TYPE:
|
||||
constant.f32 = abs(constant.f32);
|
||||
constant.f32 = std::abs(constant.f32);
|
||||
break;
|
||||
case FLOAT64_TYPE:
|
||||
constant.f64 = abs(constant.f64);
|
||||
constant.f64 = std::abs(constant.f64);
|
||||
break;
|
||||
case VEC128_TYPE:
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
@@ -452,10 +452,10 @@ void Value::Abs() {
|
||||
void Value::Sqrt() {
|
||||
switch (type) {
|
||||
case FLOAT32_TYPE:
|
||||
constant.f32 = 1.0f / sqrtf(constant.f32);
|
||||
constant.f32 = 1.0f / std::sqrtf(constant.f32);
|
||||
break;
|
||||
case FLOAT64_TYPE:
|
||||
constant.f64 = 1.0 / sqrt(constant.f64);
|
||||
constant.f64 = 1.0 / std::sqrt(constant.f64);
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(type);
|
||||
@@ -466,10 +466,10 @@ void Value::Sqrt() {
|
||||
void Value::RSqrt() {
|
||||
switch (type) {
|
||||
case FLOAT32_TYPE:
|
||||
constant.f32 = sqrt(constant.f32);
|
||||
constant.f32 = std::sqrt(constant.f32);
|
||||
break;
|
||||
case FLOAT64_TYPE:
|
||||
constant.f64 = sqrt(constant.f64);
|
||||
constant.f64 = std::sqrt(constant.f64);
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(type);
|
||||
|
||||
@@ -113,8 +113,8 @@ class Value {
|
||||
double get_constant(double) const { return constant.f64; }
|
||||
vec128_t get_constant(vec128_t&) const { return constant.v128; }
|
||||
|
||||
void set_zero(TypeName type) {
|
||||
this->type = type;
|
||||
void set_zero(TypeName new_type) {
|
||||
type = new_type;
|
||||
flags |= VALUE_IS_CONSTANT;
|
||||
constant.v128.low = constant.v128.high = 0;
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ bool MMIOHandler::HandleAccessFault(void* thread_state,
|
||||
}
|
||||
} else if (is_store) {
|
||||
// Store of a register value - read register, swap, write to range.
|
||||
uint64_t value;
|
||||
uint64_t value = 0;
|
||||
if ((arg2_type & BE::REGISTER_TYPE) == BE::REGISTER_TYPE) {
|
||||
uint32_t be_reg_index;
|
||||
if (!xe::bit_scan_forward(arg2_type & 0xFFFF, &be_reg_index)) {
|
||||
|
||||
@@ -30,10 +30,6 @@
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
// TODO(benvanik): remove when enums converted.
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::cpu::backend;
|
||||
|
||||
using PPCContext = xe::cpu::frontend::PPCContext;
|
||||
|
||||
void InitializeIfNeeded();
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
using namespace xe::cpu;
|
||||
|
||||
using PPCContext = xe::cpu::frontend::PPCContext;
|
||||
|
||||
thread_local ThreadState* thread_state_ = nullptr;
|
||||
@@ -55,7 +53,7 @@ ThreadState::ThreadState(Processor* processor, uint32_t thread_id,
|
||||
uint32_t stack_padding =
|
||||
uint32_t(xe::memory::page_size()); // Host page size.
|
||||
uint32_t actual_stack_size = stack_padding + stack_size;
|
||||
bool top_down;
|
||||
bool top_down = false;
|
||||
switch (stack_type) {
|
||||
case ThreadStackType::kKernelStack:
|
||||
top_down = true;
|
||||
|
||||
@@ -26,13 +26,11 @@
|
||||
namespace xe {
|
||||
namespace cpu {
|
||||
|
||||
using namespace xe::cpu;
|
||||
using namespace xe::kernel;
|
||||
|
||||
using PPCContext = xe::cpu::frontend::PPCContext;
|
||||
|
||||
void UndefinedImport(PPCContext* ppc_context,
|
||||
kernel::KernelState* kernel_state) {
|
||||
void UndefinedImport(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||
XELOGE("call to undefined import");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user