mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-01-02 05:30:53 +00:00
Implemented boolean && /
This commit is contained in:
parent
8a7f5bde39
commit
b2f1e1abe3
@ -179,6 +179,7 @@ public class Compiler {
|
||||
optimizations.add(new Pass2SelfPhiElimination(program));
|
||||
optimizations.add(new Pass2RedundantPhiElimination(program));
|
||||
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
||||
optimizations.add(new Pass2ConditionalAndOrRewriting(program));
|
||||
optimizations.add(new Pass2ConstantIdentification(program));
|
||||
optimizations.add(new Pass2ConstantAdditionElimination(program));
|
||||
optimizations.add(new Pass2ConstantIfs(program));
|
||||
@ -186,7 +187,6 @@ public class Compiler {
|
||||
optimizations.add(new Pass2TypeInference(program));
|
||||
optimizations.add(new PassNEliminateUnusedVars(program));
|
||||
optimizations.add(new Pass2NopCastElimination(program));
|
||||
//optimizations.add(new Pass2ConstantIfs(program));
|
||||
optimizations.add(new Pass2EliminateUnusedBlocks(program));
|
||||
pass2OptimizeSSA(optimizations);
|
||||
|
||||
|
@ -297,8 +297,6 @@ public class AsmFragmentInstanceSpec {
|
||||
return "vds";
|
||||
} else if(SymbolType.STRING.equals(type)) {
|
||||
return "pbu";
|
||||
} else if(SymbolType.BOOLEAN.equals(type)) {
|
||||
return "vbo";
|
||||
} else if(type instanceof SymbolTypePointer) {
|
||||
SymbolType elementType = ((SymbolTypePointer) type).getElementType();
|
||||
if(SymbolType.isByte(elementType)) {
|
||||
@ -328,8 +326,7 @@ public class AsmFragmentInstanceSpec {
|
||||
if(
|
||||
Registers.RegisterType.ZP_BYTE.equals(register.getType()) ||
|
||||
Registers.RegisterType.ZP_WORD.equals(register.getType()) ||
|
||||
Registers.RegisterType.ZP_DWORD.equals(register.getType()) ||
|
||||
Registers.RegisterType.ZP_BOOL.equals(register.getType())
|
||||
Registers.RegisterType.ZP_DWORD.equals(register.getType())
|
||||
) {
|
||||
// Examine if the ZP register is already bound
|
||||
Registers.RegisterZp registerZp = (Registers.RegisterZp) register;
|
||||
|
@ -0,0 +1,144 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.ControlFlowBlock;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
import dk.camelot64.kickc.model.operators.Operators;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementAssignment;
|
||||
import dk.camelot64.kickc.model.statements.StatementConditionalJump;
|
||||
import dk.camelot64.kickc.model.symbols.Label;
|
||||
import dk.camelot64.kickc.model.symbols.Scope;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Compiler Pass rewriting conditional jumps that use && or || operators
|
||||
*/
|
||||
public class Pass2ConditionalAndOrRewriting extends Pass2SsaOptimization {
|
||||
|
||||
public Pass2ConditionalAndOrRewriting(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
VariableRef obsoleteConditionVar = findAndRewriteBooleanCondition();
|
||||
if(obsoleteConditionVar!=null) {
|
||||
Collection<VariableRef> obsoleteVars = new ArrayList<>();
|
||||
obsoleteVars.add(obsoleteConditionVar);
|
||||
removeAssignments(obsoleteVars);
|
||||
deleteSymbols(obsoleteVars);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look through the entire program looking for an if() condition that uses &&, || or !.
|
||||
* When found rewrite it (adding blocks)
|
||||
* @return Null if no condition was found to rewrite. The now obsolete variable containing the && / || / ! to be removed.
|
||||
*/
|
||||
private VariableRef findAndRewriteBooleanCondition() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
final Map<LValue, StatementAssignment> assignments = getAllAssignments();
|
||||
final Map<RValue, List<Statement>> usages = getAllUsages();
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementConditionalJump) {
|
||||
StatementConditionalJump conditional = (StatementConditionalJump) statement;
|
||||
if(conditional.getrValue1()==null && conditional.getOperator()==null) {
|
||||
RValue conditionRValue = conditional.getrValue2();
|
||||
if(conditionRValue instanceof VariableRef && usages.get(conditionRValue).size() == 1) {
|
||||
VariableRef conditionVar = (VariableRef) conditionRValue;
|
||||
StatementAssignment conditionAssignment = assignments.get(conditionVar);
|
||||
if(Operators.LOGIC_AND.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical && condition - rewrite to if(c1) if(c2) { xx }
|
||||
rewriteLogicAnd(block, conditional, conditionAssignment);
|
||||
return conditionVar;
|
||||
} else if(Operators.LOGIC_OR.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical || condition - rewrite to if(c1) goto x else if(c2) goto x else goto end, x:{ xx } end:
|
||||
rewriteLogicOr(block, conditional, conditionAssignment);
|
||||
return conditionVar;
|
||||
} else if(Operators.LOGIC_NOT.equals(conditionAssignment.getOperator())) {
|
||||
// Found if() with logical ! condition - rewrite to if(!c1) goto x else goto end, x:{ xx } end:
|
||||
rewriteLogicNot(block, conditional, conditionAssignment);
|
||||
return conditionVar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite logical && condition if(c1&&c2) { xx } to if(c1) if(c2) { xx }
|
||||
* @param block The block containing the current if()
|
||||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
*/
|
||||
private void rewriteLogicAnd(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
// Found an if with a logical && condition - rewrite to if(c1) if(c2) { xx }
|
||||
getLog().append("Rewriting && if()-condition to two if()s "+conditionAssignment.toString(getProgram(), false));
|
||||
ScopeRef currentScopeRef = block.getScope();
|
||||
Scope currentScope = getScope().getScope(currentScopeRef);
|
||||
// Add a new block containing the second part of the && condition expression
|
||||
Label newBlockLabel = currentScope.addLabelIntermediate();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
newBlock.getStatements().add(new StatementConditionalJump(conditionAssignment.getrValue2(), conditional.getDestination()));
|
||||
newBlock.setDefaultSuccessor(block.getDefaultSuccessor());
|
||||
newBlock.setConditionalSuccessor(conditional.getDestination());
|
||||
// Rewrite the conditional to use only the first part of the && condition expression
|
||||
conditional.setDestination(newBlockLabel.getRef());
|
||||
block.setConditionalSuccessor(newBlockLabel.getRef());
|
||||
conditional.setrValue2(conditionAssignment.getrValue1());
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite logical || condition if(c1&&c2) { xx } to if(c1) goto x else if(c2) goto x else goto end, x:{ xx } end:
|
||||
* @param block The block containing the current if()
|
||||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
*/
|
||||
private void rewriteLogicOr(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
getLog().append("Rewriting || if()-condition to two if()s "+conditionAssignment.toString(getProgram(), false));
|
||||
ScopeRef currentScopeRef = block.getScope();
|
||||
Scope currentScope = getScope().getScope(currentScopeRef);
|
||||
// Add a new block containing the second part of the && condition expression
|
||||
Label newBlockLabel = currentScope.addLabelIntermediate();
|
||||
ControlFlowBlock newBlock = new ControlFlowBlock(newBlockLabel.getRef(), currentScopeRef);
|
||||
getGraph().addBlock(newBlock);
|
||||
newBlock.getStatements().add(new StatementConditionalJump(conditionAssignment.getrValue2(), conditional.getDestination()));
|
||||
newBlock.setConditionalSuccessor(conditional.getDestination());
|
||||
newBlock.setDefaultSuccessor(block.getDefaultSuccessor());
|
||||
// Rewrite the conditional to use only the first part of the && condition expression
|
||||
block.setDefaultSuccessor(newBlockLabel.getRef());
|
||||
conditional.setrValue2(conditionAssignment.getrValue1());
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite logical ! condition if(!c1) { xx } to if(c1) goto end else goto x, x:{ xx } end:
|
||||
* @param block The block containing the current if()
|
||||
* @param conditional The if()-statement
|
||||
* @param conditionAssignment The assignment defining the condition variable.
|
||||
*/
|
||||
private void rewriteLogicNot(ControlFlowBlock block, StatementConditionalJump conditional, StatementAssignment conditionAssignment) {
|
||||
getLog().append("Rewriting ! if()-condition to reversed if() "+conditionAssignment.toString(getProgram(), false));
|
||||
// Rewrite the conditional to use only the first part of the && condition expression
|
||||
LabelRef defaultSuccessor = block.getDefaultSuccessor();
|
||||
LabelRef conditionalSuccessor = block.getConditionalSuccessor();
|
||||
// Change condition (to the non-negated condition)
|
||||
conditional.setrValue2(conditionAssignment.getrValue2());
|
||||
// Swap successors
|
||||
conditional.setDestination(defaultSuccessor);
|
||||
block.setConditionalSuccessor(defaultSuccessor);
|
||||
block.setDefaultSuccessor(conditionalSuccessor);
|
||||
}
|
||||
|
||||
}
|
@ -21,9 +21,6 @@ public class Pass2ConditionalJumpSimplification extends Pass2SsaOptimization {
|
||||
super(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminate alias assignments replacing them with the aliased variable.
|
||||
*/
|
||||
@Override
|
||||
public boolean step() {
|
||||
final Map<LValue, StatementAssignment> assignments = getAllAssignments();
|
||||
|
@ -53,9 +53,6 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
|
||||
potentials.add(Registers.getRegisterX());
|
||||
potentials.add(Registers.getRegisterY());
|
||||
}
|
||||
if(registerType.equals(Registers.RegisterType.ZP_BOOL) && !varRefExtracted(equivalenceClass)) {
|
||||
potentials.add(Registers.getRegisterA());
|
||||
}
|
||||
registerPotentials.setPotentialRegisters(equivalenceClass, potentials);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,16 @@
|
||||
// A Minimal test of boolean variables.
|
||||
// Boolean variables are bytes under the hood
|
||||
// 0: false, !=0 : true
|
||||
|
||||
const byte* screen = $400;
|
||||
// A test of boolean conditions using && || and !
|
||||
|
||||
void main() {
|
||||
bool_and();
|
||||
bool_or();
|
||||
bool_not();
|
||||
bool_complex();
|
||||
}
|
||||
|
||||
void bool_and() {
|
||||
const byte* screen = $400;
|
||||
for( byte i : 0..20) {
|
||||
boolean o1 = i<10;
|
||||
boolean o2 = (i&1)==0;
|
||||
if( o1 && o2 ) {
|
||||
if( (i<10) && ((i&1)==0) ) {
|
||||
screen[i] = '*';
|
||||
} else {
|
||||
screen[i] = ' ';
|
||||
@ -16,3 +18,37 @@ void main() {
|
||||
}
|
||||
}
|
||||
|
||||
void bool_or() {
|
||||
const byte* screen = $428;
|
||||
for( byte i : 0..20) {
|
||||
if( (i<10) || ((i&1)==0) ) {
|
||||
screen[i] = '*';
|
||||
} else {
|
||||
screen[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bool_not() {
|
||||
const byte* screen = $450;
|
||||
for( byte i : 0..20) {
|
||||
boolean o1 = (i&1)==0;
|
||||
if( !((i<10) || ((i&1)==0)) ) {
|
||||
screen[i] = '*';
|
||||
} else {
|
||||
screen[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bool_complex() {
|
||||
const byte* screen = $478;
|
||||
for( byte i : 0..20) {
|
||||
boolean o1 = (i&1)==0;
|
||||
if( ((i<10) && ((i&1)==0)) || !((i<10) || ((i&1)==0)) ) {
|
||||
screen[i] = '*';
|
||||
} else {
|
||||
screen[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -424,6 +424,22 @@ Alias (boolean) bool_const_vars::b1#0 = (boolean~) bool_const_vars::$3
|
||||
Alias (boolean) bool_const_vars::b2#0 = (boolean~) bool_const_vars::$7
|
||||
Alias (boolean) bool_const_vars::b#0 = (boolean~) bool_const_vars::$10
|
||||
Succesful SSA optimization Pass2AliasElimination
|
||||
Rewriting || if()-condition to two if()s (boolean) bool_const_vars::b#0 ← (boolean~) bool_const_vars::$9 || false
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Rewriting && if()-condition to two if()s (boolean~) bool_const_vars::$9 ← (boolean) bool_const_vars::b1#0 && (boolean~) bool_const_vars::$8
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Rewriting || if()-condition to two if()s (boolean) bool_const_vars::b1#0 ← (boolean~) bool_const_vars::$0 || (boolean~) bool_const_vars::$2
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Rewriting || if()-condition to two if()s (boolean~) bool_const_inline::$8 ← (boolean~) bool_const_inline::$5 || (boolean~) bool_const_inline::$7
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Rewriting || if()-condition to two if()s (boolean~) bool_const_inline::$5 ← (boolean~) bool_const_inline::$0 || (boolean~) bool_const_inline::$4
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Rewriting ! if()-condition to reversed if() (boolean~) bool_const_vars::$8 ← ! (boolean) bool_const_vars::b2#0
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Rewriting || if()-condition to two if()s (boolean) bool_const_vars::b2#0 ← (boolean~) bool_const_vars::$4 || (boolean~) bool_const_vars::$6
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Rewriting && if()-condition to two if()s (boolean~) bool_const_inline::$4 ← (boolean~) bool_const_inline::$2 && (boolean~) bool_const_inline::$3
|
||||
Succesful SSA optimization Pass2ConditionalAndOrRewriting
|
||||
Constant (const byte*) SCREEN#0 = ((byte*))1024
|
||||
Constant (const boolean) bool_const_if::b#0 = true
|
||||
Constant (const byte) bool_const_vars::a#0 = 14
|
||||
@ -440,18 +456,6 @@ Constant (const boolean) bool_const_inline::$2 = bool_const_inline::a#0>=bool_co
|
||||
Constant (const boolean) bool_const_inline::$3 = bool_const_inline::a#0==15
|
||||
Constant (const boolean) bool_const_inline::$7 = 21>=bool_const_inline::a#0
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const boolean) bool_const_vars::b1#0 = bool_const_vars::$0||bool_const_vars::$2
|
||||
Constant (const boolean) bool_const_vars::b2#0 = bool_const_vars::$4||bool_const_vars::$6
|
||||
Constant (const boolean) bool_const_inline::$4 = bool_const_inline::$2&&bool_const_inline::$3
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const boolean) bool_const_vars::$8 = !bool_const_vars::b2#0
|
||||
Constant (const boolean) bool_const_inline::$5 = bool_const_inline::$0||bool_const_inline::$4
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const boolean) bool_const_vars::$9 = bool_const_vars::b1#0&&bool_const_vars::$8
|
||||
Constant (const boolean) bool_const_inline::$8 = bool_const_inline::$5||bool_const_inline::$7
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Constant (const boolean) bool_const_vars::b#0 = bool_const_vars::$9||false
|
||||
Succesful SSA optimization Pass2ConstantIdentification
|
||||
Consolidated array index constant in *(SCREEN#0+0)
|
||||
Consolidated array index constant in *(SCREEN#0+0)
|
||||
Consolidated array index constant in *(SCREEN#0+1)
|
||||
@ -460,40 +464,43 @@ Consolidated array index constant in *(SCREEN#0+2)
|
||||
Consolidated array index constant in *(SCREEN#0+2)
|
||||
Succesful SSA optimization Pass2ConstantAdditionElimination
|
||||
if() condition always true - replacing block destination if((const boolean) bool_const_if::b#0) goto bool_const_if::@1
|
||||
if() condition always false - eliminating if((const boolean) bool_const_vars::b#0) goto bool_const_vars::@1
|
||||
if() condition always true - replacing block destination if((const boolean) bool_const_inline::$8) goto bool_const_inline::@1
|
||||
if() condition always false - eliminating if((const boolean) bool_const_vars::$0) goto bool_const_vars::@6
|
||||
if() condition always true - replacing block destination if((const boolean) bool_const_inline::$0) goto bool_const_inline::@1
|
||||
if() condition always false - eliminating if(false) goto bool_const_vars::@1
|
||||
if() condition always true - replacing block destination if((const boolean) bool_const_vars::$4) goto bool_const_vars::@5
|
||||
if() condition always true - replacing block destination if((const boolean) bool_const_vars::$2) goto bool_const_vars::@6
|
||||
if() condition always false - eliminating if((const boolean) bool_const_inline::$7) goto bool_const_inline::@1
|
||||
if() condition always true - replacing block destination if((const boolean) bool_const_inline::$2) goto bool_const_inline::@7
|
||||
if() condition always true - replacing block destination if((const boolean) bool_const_vars::$6) goto bool_const_vars::@5
|
||||
if() condition always false - eliminating if((const boolean) bool_const_inline::$3) goto bool_const_inline::@1
|
||||
Succesful SSA optimization Pass2ConstantIfs
|
||||
Eliminating unused constant (const boolean) bool_const_if::b#0
|
||||
Eliminating unused constant (const boolean) bool_const_vars::b#0
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$8
|
||||
Succesful SSA optimization PassNEliminateUnusedVars
|
||||
Eliminating unused constant (const boolean) bool_const_vars::$9
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$7
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$5
|
||||
Succesful SSA optimization PassNEliminateUnusedVars
|
||||
Eliminating unused constant (const boolean) bool_const_vars::b1#0
|
||||
Eliminating unused constant (const boolean) bool_const_vars::$8
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$0
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$4
|
||||
Succesful SSA optimization PassNEliminateUnusedVars
|
||||
Eliminating unused constant (const boolean) bool_const_vars::$0
|
||||
Eliminating unused constant (const boolean) bool_const_vars::$2
|
||||
Eliminating unused constant (const boolean) bool_const_vars::b2#0
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$2
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$3
|
||||
Succesful SSA optimization PassNEliminateUnusedVars
|
||||
Eliminating unused constant (const boolean) bool_const_vars::$4
|
||||
Eliminating unused constant (const boolean) bool_const_vars::$6
|
||||
Eliminating unused constant (const byte) bool_const_inline::a#0
|
||||
Eliminating unused constant (const signed byte/signed word/signed dword) bool_const_inline::$1
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$0
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$2
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$3
|
||||
Eliminating unused constant (const boolean) bool_const_inline::$7
|
||||
Succesful SSA optimization PassNEliminateUnusedVars
|
||||
Eliminating unused constant (const byte) bool_const_vars::a#0
|
||||
Eliminating unused constant (const signed byte/signed word/signed dword) bool_const_vars::$5
|
||||
Eliminating unused constant (const byte) bool_const_inline::a#0
|
||||
Eliminating unused constant (const signed byte/signed word/signed dword) bool_const_inline::$1
|
||||
Succesful SSA optimization PassNEliminateUnusedVars
|
||||
Removing unused block bool_const_if::@3
|
||||
Removing unused block bool_const_vars::@1
|
||||
Removing unused block bool_const_inline::@3
|
||||
Removing unused block bool_const_inline::@5
|
||||
Removing unused block bool_const_inline::@6
|
||||
Removing unused block bool_const_vars::@8
|
||||
Removing unused block bool_const_inline::@7
|
||||
Succesful SSA optimization Pass2EliminateUnusedBlocks
|
||||
Culled Empty Block (label) bool_const_vars::@5
|
||||
Culled Empty Block (label) bool_const_vars::@6
|
||||
Culled Empty Block (label) bool_const_vars::@7
|
||||
Succesful SSA optimization Pass2CullEmptyBlocks
|
||||
OPTIMIZING CONTROL FLOW GRAPH
|
||||
Block Sequence Planned @begin @4 @end main main::@1 main::@2 main::@return bool_const_inline bool_const_inline::@1 bool_const_inline::@return bool_const_vars bool_const_vars::@3 bool_const_vars::@return bool_const_if bool_const_if::@1 bool_const_if::@return
|
||||
Block Sequence Planned @begin @4 @end main main::@1 main::@2 main::@return bool_const_inline bool_const_inline::@1 bool_const_inline::@return bool_const_vars bool_const_vars::@3 bool_const_vars::@return bool_const_if bool_const_if::@1 bool_const_if::@return
|
||||
|
@ -1,32 +1,79 @@
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label screen = $400
|
||||
jsr main
|
||||
main: {
|
||||
.label o1 = 2
|
||||
jsr bool_and
|
||||
jsr bool_or
|
||||
jsr bool_not
|
||||
jsr bool_complex
|
||||
rts
|
||||
}
|
||||
bool_complex: {
|
||||
.label screen = $478
|
||||
ldy #0
|
||||
b1:
|
||||
tya
|
||||
and #1
|
||||
tax
|
||||
tya
|
||||
and #1
|
||||
cpy #$a
|
||||
bcc b8
|
||||
b7:
|
||||
cpy #$a
|
||||
bcc b4
|
||||
cmp #0
|
||||
beq b4
|
||||
b2:
|
||||
lda #'*'
|
||||
sta screen,y
|
||||
b3:
|
||||
iny
|
||||
cpy #$15
|
||||
bne b1
|
||||
rts
|
||||
b4:
|
||||
lda #' '
|
||||
sta screen,y
|
||||
jmp b3
|
||||
b8:
|
||||
cpx #0
|
||||
beq b2
|
||||
jmp b7
|
||||
}
|
||||
bool_not: {
|
||||
.label screen = $450
|
||||
ldx #0
|
||||
b1:
|
||||
cpx #$a
|
||||
lda #0
|
||||
rol
|
||||
eor #1
|
||||
sta o1
|
||||
txa
|
||||
and #1
|
||||
sec
|
||||
sbc #0
|
||||
beq !+
|
||||
lda #$ff
|
||||
!:
|
||||
eor #$ff
|
||||
cpx #$a
|
||||
bcc b4
|
||||
cmp #0
|
||||
beq !+
|
||||
lda #$ff
|
||||
!:
|
||||
and o1
|
||||
beq b4
|
||||
lda #'*'
|
||||
sta screen,x
|
||||
b3:
|
||||
inx
|
||||
cpx #$15
|
||||
bne b1
|
||||
rts
|
||||
b4:
|
||||
lda #' '
|
||||
sta screen,x
|
||||
jmp b3
|
||||
}
|
||||
bool_or: {
|
||||
.label screen = $428
|
||||
ldx #0
|
||||
b1:
|
||||
txa
|
||||
and #1
|
||||
cpx #$a
|
||||
bcc b2
|
||||
cmp #0
|
||||
bne b2
|
||||
beq b2
|
||||
lda #' '
|
||||
sta screen,x
|
||||
b3:
|
||||
@ -39,3 +86,28 @@ main: {
|
||||
sta screen,x
|
||||
jmp b3
|
||||
}
|
||||
bool_and: {
|
||||
.label screen = $400
|
||||
ldx #0
|
||||
b1:
|
||||
txa
|
||||
and #1
|
||||
cpx #$a
|
||||
bcc b7
|
||||
b4:
|
||||
lda #' '
|
||||
sta screen,x
|
||||
b3:
|
||||
inx
|
||||
cpx #$15
|
||||
bne b1
|
||||
rts
|
||||
b7:
|
||||
cmp #0
|
||||
beq b2
|
||||
jmp b4
|
||||
b2:
|
||||
lda #'*'
|
||||
sta screen,x
|
||||
jmp b3
|
||||
}
|
||||
|
@ -1,33 +1,131 @@
|
||||
@begin: scope:[] from
|
||||
[0] phi() [ ] ( )
|
||||
to:@1
|
||||
@1: scope:[] from @begin
|
||||
to:@5
|
||||
@5: scope:[] from @begin
|
||||
[1] phi() [ ] ( )
|
||||
[2] call main param-assignment [ ] ( )
|
||||
to:@end
|
||||
@end: scope:[] from @1
|
||||
@end: scope:[] from @5
|
||||
[3] phi() [ ] ( )
|
||||
main: scope:[main] from @1
|
||||
main: scope:[main] from @5
|
||||
[4] phi() [ ] ( main:2 [ ] )
|
||||
[5] call bool_and param-assignment [ ] ( main:2 [ ] )
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@3
|
||||
[5] (byte) main::i#2 ← phi( main/(byte/signed byte/word/signed word/dword/signed dword) 0 main::@3/(byte) main::i#1 ) [ main::i#2 ] ( main:2 [ main::i#2 ] )
|
||||
[6] (boolean) main::o1#0 ← (byte) main::i#2 < (byte/signed byte/word/signed word/dword/signed dword) 10 [ main::i#2 main::o1#0 ] ( main:2 [ main::i#2 main::o1#0 ] )
|
||||
[7] (byte~) main::$1 ← (byte) main::i#2 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ main::i#2 main::o1#0 main::$1 ] ( main:2 [ main::i#2 main::o1#0 main::$1 ] )
|
||||
[8] (boolean) main::o2#0 ← (byte~) main::$1 == (byte/signed byte/word/signed word/dword/signed dword) 0 [ main::i#2 main::o1#0 main::o2#0 ] ( main:2 [ main::i#2 main::o1#0 main::o2#0 ] )
|
||||
[9] (boolean~) main::$3 ← (boolean) main::o1#0 && (boolean) main::o2#0 [ main::i#2 main::$3 ] ( main:2 [ main::i#2 main::$3 ] )
|
||||
[10] if((boolean~) main::$3) goto main::@2 [ main::i#2 ] ( main:2 [ main::i#2 ] )
|
||||
to:main::@4
|
||||
main::@4: scope:[main] from main::@1
|
||||
[11] *((const byte*) screen#0 + (byte) main::i#2) ← (byte) ' ' [ main::i#2 ] ( main:2 [ main::i#2 ] )
|
||||
main::@1: scope:[main] from main
|
||||
[6] phi() [ ] ( main:2 [ ] )
|
||||
[7] call bool_or param-assignment [ ] ( main:2 [ ] )
|
||||
to:main::@2
|
||||
main::@2: scope:[main] from main::@1
|
||||
[8] phi() [ ] ( main:2 [ ] )
|
||||
[9] call bool_not param-assignment [ ] ( main:2 [ ] )
|
||||
to:main::@3
|
||||
main::@3: scope:[main] from main::@2 main::@4
|
||||
[12] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] ( main:2 [ main::i#1 ] )
|
||||
[13] if((byte) main::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 21) goto main::@1 [ main::i#1 ] ( main:2 [ main::i#1 ] )
|
||||
main::@3: scope:[main] from main::@2
|
||||
[10] phi() [ ] ( main:2 [ ] )
|
||||
[11] call bool_complex param-assignment [ ] ( main:2 [ ] )
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@3
|
||||
[14] return [ ] ( main:2 [ ] )
|
||||
[12] return [ ] ( main:2 [ ] )
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[15] *((const byte*) screen#0 + (byte) main::i#2) ← (byte) '*' [ main::i#2 ] ( main:2 [ main::i#2 ] )
|
||||
to:main::@3
|
||||
bool_complex: scope:[bool_complex] from main::@3
|
||||
[13] phi() [ ] ( main:2::bool_complex:11 [ ] )
|
||||
to:bool_complex::@1
|
||||
bool_complex::@1: scope:[bool_complex] from bool_complex bool_complex::@3
|
||||
[14] (byte) bool_complex::i#2 ← phi( bool_complex/(byte/signed byte/word/signed word/dword/signed dword) 0 bool_complex::@3/(byte) bool_complex::i#1 ) [ bool_complex::i#2 ] ( main:2::bool_complex:11 [ bool_complex::i#2 ] )
|
||||
[15] (byte~) bool_complex::$3 ← (byte) bool_complex::i#2 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ bool_complex::i#2 bool_complex::$3 ] ( main:2::bool_complex:11 [ bool_complex::i#2 bool_complex::$3 ] )
|
||||
[16] (byte~) bool_complex::$7 ← (byte) bool_complex::i#2 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ bool_complex::i#2 bool_complex::$3 bool_complex::$7 ] ( main:2::bool_complex:11 [ bool_complex::i#2 bool_complex::$3 bool_complex::$7 ] )
|
||||
[17] if((byte) bool_complex::i#2<(byte/signed byte/word/signed word/dword/signed dword) 10) goto bool_complex::@8 [ bool_complex::i#2 bool_complex::$3 bool_complex::$7 ] ( main:2::bool_complex:11 [ bool_complex::i#2 bool_complex::$3 bool_complex::$7 ] )
|
||||
to:bool_complex::@7
|
||||
bool_complex::@7: scope:[bool_complex] from bool_complex::@1 bool_complex::@8
|
||||
[18] if((byte) bool_complex::i#2<(byte/signed byte/word/signed word/dword/signed dword) 10) goto bool_complex::@4 [ bool_complex::i#2 bool_complex::$7 ] ( main:2::bool_complex:11 [ bool_complex::i#2 bool_complex::$7 ] )
|
||||
to:bool_complex::@9
|
||||
bool_complex::@9: scope:[bool_complex] from bool_complex::@7
|
||||
[19] if((byte~) bool_complex::$7==(byte/signed byte/word/signed word/dword/signed dword) 0) goto bool_complex::@4 [ bool_complex::i#2 ] ( main:2::bool_complex:11 [ bool_complex::i#2 ] )
|
||||
to:bool_complex::@2
|
||||
bool_complex::@2: scope:[bool_complex] from bool_complex::@8 bool_complex::@9
|
||||
[20] *((const byte*) bool_complex::screen#0 + (byte) bool_complex::i#2) ← (byte) '*' [ bool_complex::i#2 ] ( main:2::bool_complex:11 [ bool_complex::i#2 ] )
|
||||
to:bool_complex::@3
|
||||
bool_complex::@3: scope:[bool_complex] from bool_complex::@2 bool_complex::@4
|
||||
[21] (byte) bool_complex::i#1 ← ++ (byte) bool_complex::i#2 [ bool_complex::i#1 ] ( main:2::bool_complex:11 [ bool_complex::i#1 ] )
|
||||
[22] if((byte) bool_complex::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 21) goto bool_complex::@1 [ bool_complex::i#1 ] ( main:2::bool_complex:11 [ bool_complex::i#1 ] )
|
||||
to:bool_complex::@return
|
||||
bool_complex::@return: scope:[bool_complex] from bool_complex::@3
|
||||
[23] return [ ] ( main:2::bool_complex:11 [ ] )
|
||||
to:@return
|
||||
bool_complex::@4: scope:[bool_complex] from bool_complex::@7 bool_complex::@9
|
||||
[24] *((const byte*) bool_complex::screen#0 + (byte) bool_complex::i#2) ← (byte) ' ' [ bool_complex::i#2 ] ( main:2::bool_complex:11 [ bool_complex::i#2 ] )
|
||||
to:bool_complex::@3
|
||||
bool_complex::@8: scope:[bool_complex] from bool_complex::@1
|
||||
[25] if((byte~) bool_complex::$3==(byte/signed byte/word/signed word/dword/signed dword) 0) goto bool_complex::@2 [ bool_complex::i#2 bool_complex::$7 ] ( main:2::bool_complex:11 [ bool_complex::i#2 bool_complex::$7 ] )
|
||||
to:bool_complex::@7
|
||||
bool_not: scope:[bool_not] from main::@2
|
||||
[26] phi() [ ] ( main:2::bool_not:9 [ ] )
|
||||
to:bool_not::@1
|
||||
bool_not::@1: scope:[bool_not] from bool_not bool_not::@3
|
||||
[27] (byte) bool_not::i#2 ← phi( bool_not/(byte/signed byte/word/signed word/dword/signed dword) 0 bool_not::@3/(byte) bool_not::i#1 ) [ bool_not::i#2 ] ( main:2::bool_not:9 [ bool_not::i#2 ] )
|
||||
[28] (byte~) bool_not::$3 ← (byte) bool_not::i#2 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ bool_not::i#2 bool_not::$3 ] ( main:2::bool_not:9 [ bool_not::i#2 bool_not::$3 ] )
|
||||
[29] if((byte) bool_not::i#2<(byte/signed byte/word/signed word/dword/signed dword) 10) goto bool_not::@4 [ bool_not::i#2 bool_not::$3 ] ( main:2::bool_not:9 [ bool_not::i#2 bool_not::$3 ] )
|
||||
to:bool_not::@7
|
||||
bool_not::@7: scope:[bool_not] from bool_not::@1
|
||||
[30] if((byte~) bool_not::$3==(byte/signed byte/word/signed word/dword/signed dword) 0) goto bool_not::@4 [ bool_not::i#2 ] ( main:2::bool_not:9 [ bool_not::i#2 ] )
|
||||
to:bool_not::@2
|
||||
bool_not::@2: scope:[bool_not] from bool_not::@7
|
||||
[31] *((const byte*) bool_not::screen#0 + (byte) bool_not::i#2) ← (byte) '*' [ bool_not::i#2 ] ( main:2::bool_not:9 [ bool_not::i#2 ] )
|
||||
to:bool_not::@3
|
||||
bool_not::@3: scope:[bool_not] from bool_not::@2 bool_not::@4
|
||||
[32] (byte) bool_not::i#1 ← ++ (byte) bool_not::i#2 [ bool_not::i#1 ] ( main:2::bool_not:9 [ bool_not::i#1 ] )
|
||||
[33] if((byte) bool_not::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 21) goto bool_not::@1 [ bool_not::i#1 ] ( main:2::bool_not:9 [ bool_not::i#1 ] )
|
||||
to:bool_not::@return
|
||||
bool_not::@return: scope:[bool_not] from bool_not::@3
|
||||
[34] return [ ] ( main:2::bool_not:9 [ ] )
|
||||
to:@return
|
||||
bool_not::@4: scope:[bool_not] from bool_not::@1 bool_not::@7
|
||||
[35] *((const byte*) bool_not::screen#0 + (byte) bool_not::i#2) ← (byte) ' ' [ bool_not::i#2 ] ( main:2::bool_not:9 [ bool_not::i#2 ] )
|
||||
to:bool_not::@3
|
||||
bool_or: scope:[bool_or] from main::@1
|
||||
[36] phi() [ ] ( main:2::bool_or:7 [ ] )
|
||||
to:bool_or::@1
|
||||
bool_or::@1: scope:[bool_or] from bool_or bool_or::@3
|
||||
[37] (byte) bool_or::i#2 ← phi( bool_or/(byte/signed byte/word/signed word/dword/signed dword) 0 bool_or::@3/(byte) bool_or::i#1 ) [ bool_or::i#2 ] ( main:2::bool_or:7 [ bool_or::i#2 ] )
|
||||
[38] (byte~) bool_or::$1 ← (byte) bool_or::i#2 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ bool_or::i#2 bool_or::$1 ] ( main:2::bool_or:7 [ bool_or::i#2 bool_or::$1 ] )
|
||||
[39] if((byte) bool_or::i#2<(byte/signed byte/word/signed word/dword/signed dword) 10) goto bool_or::@2 [ bool_or::i#2 bool_or::$1 ] ( main:2::bool_or:7 [ bool_or::i#2 bool_or::$1 ] )
|
||||
to:bool_or::@7
|
||||
bool_or::@7: scope:[bool_or] from bool_or::@1
|
||||
[40] if((byte~) bool_or::$1==(byte/signed byte/word/signed word/dword/signed dword) 0) goto bool_or::@2 [ bool_or::i#2 ] ( main:2::bool_or:7 [ bool_or::i#2 ] )
|
||||
to:bool_or::@4
|
||||
bool_or::@4: scope:[bool_or] from bool_or::@7
|
||||
[41] *((const byte*) bool_or::screen#0 + (byte) bool_or::i#2) ← (byte) ' ' [ bool_or::i#2 ] ( main:2::bool_or:7 [ bool_or::i#2 ] )
|
||||
to:bool_or::@3
|
||||
bool_or::@3: scope:[bool_or] from bool_or::@2 bool_or::@4
|
||||
[42] (byte) bool_or::i#1 ← ++ (byte) bool_or::i#2 [ bool_or::i#1 ] ( main:2::bool_or:7 [ bool_or::i#1 ] )
|
||||
[43] if((byte) bool_or::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 21) goto bool_or::@1 [ bool_or::i#1 ] ( main:2::bool_or:7 [ bool_or::i#1 ] )
|
||||
to:bool_or::@return
|
||||
bool_or::@return: scope:[bool_or] from bool_or::@3
|
||||
[44] return [ ] ( main:2::bool_or:7 [ ] )
|
||||
to:@return
|
||||
bool_or::@2: scope:[bool_or] from bool_or::@1 bool_or::@7
|
||||
[45] *((const byte*) bool_or::screen#0 + (byte) bool_or::i#2) ← (byte) '*' [ bool_or::i#2 ] ( main:2::bool_or:7 [ bool_or::i#2 ] )
|
||||
to:bool_or::@3
|
||||
bool_and: scope:[bool_and] from main
|
||||
[46] phi() [ ] ( main:2::bool_and:5 [ ] )
|
||||
to:bool_and::@1
|
||||
bool_and::@1: scope:[bool_and] from bool_and bool_and::@3
|
||||
[47] (byte) bool_and::i#2 ← phi( bool_and/(byte/signed byte/word/signed word/dword/signed dword) 0 bool_and::@3/(byte) bool_and::i#1 ) [ bool_and::i#2 ] ( main:2::bool_and:5 [ bool_and::i#2 ] )
|
||||
[48] (byte~) bool_and::$1 ← (byte) bool_and::i#2 & (byte/signed byte/word/signed word/dword/signed dword) 1 [ bool_and::i#2 bool_and::$1 ] ( main:2::bool_and:5 [ bool_and::i#2 bool_and::$1 ] )
|
||||
[49] if((byte) bool_and::i#2<(byte/signed byte/word/signed word/dword/signed dword) 10) goto bool_and::@7 [ bool_and::i#2 bool_and::$1 ] ( main:2::bool_and:5 [ bool_and::i#2 bool_and::$1 ] )
|
||||
to:bool_and::@4
|
||||
bool_and::@4: scope:[bool_and] from bool_and::@1 bool_and::@7
|
||||
[50] *((const byte*) bool_and::screen#0 + (byte) bool_and::i#2) ← (byte) ' ' [ bool_and::i#2 ] ( main:2::bool_and:5 [ bool_and::i#2 ] )
|
||||
to:bool_and::@3
|
||||
bool_and::@3: scope:[bool_and] from bool_and::@2 bool_and::@4
|
||||
[51] (byte) bool_and::i#1 ← ++ (byte) bool_and::i#2 [ bool_and::i#1 ] ( main:2::bool_and:5 [ bool_and::i#1 ] )
|
||||
[52] if((byte) bool_and::i#1!=(byte/signed byte/word/signed word/dword/signed dword) 21) goto bool_and::@1 [ bool_and::i#1 ] ( main:2::bool_and:5 [ bool_and::i#1 ] )
|
||||
to:bool_and::@return
|
||||
bool_and::@return: scope:[bool_and] from bool_and::@3
|
||||
[53] return [ ] ( main:2::bool_and:5 [ ] )
|
||||
to:@return
|
||||
bool_and::@7: scope:[bool_and] from bool_and::@1
|
||||
[54] if((byte~) bool_and::$1==(byte/signed byte/word/signed word/dword/signed dword) 0) goto bool_and::@2 [ bool_and::i#2 ] ( main:2::bool_and:5 [ bool_and::i#2 ] )
|
||||
to:bool_and::@4
|
||||
bool_and::@2: scope:[bool_and] from bool_and::@7
|
||||
[55] *((const byte*) bool_and::screen#0 + (byte) bool_and::i#2) ← (byte) '*' [ bool_and::i#2 ] ( main:2::bool_and:5 [ bool_and::i#2 ] )
|
||||
to:bool_and::@3
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,26 +1,73 @@
|
||||
(label) @1
|
||||
(label) @5
|
||||
(label) @begin
|
||||
(label) @end
|
||||
(void()) bool_and()
|
||||
(byte~) bool_and::$1 reg byte a 11.0
|
||||
(label) bool_and::@1
|
||||
(label) bool_and::@2
|
||||
(label) bool_and::@3
|
||||
(label) bool_and::@4
|
||||
(label) bool_and::@7
|
||||
(label) bool_and::@return
|
||||
(byte) bool_and::i
|
||||
(byte) bool_and::i#1 reg byte x 16.5
|
||||
(byte) bool_and::i#2 reg byte x 11.0
|
||||
(byte*) bool_and::screen
|
||||
(const byte*) bool_and::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024
|
||||
(void()) bool_complex()
|
||||
(byte~) bool_complex::$3 reg byte x 7.333333333333333
|
||||
(byte~) bool_complex::$7 reg byte a 5.5
|
||||
(label) bool_complex::@1
|
||||
(label) bool_complex::@2
|
||||
(label) bool_complex::@3
|
||||
(label) bool_complex::@4
|
||||
(label) bool_complex::@7
|
||||
(label) bool_complex::@8
|
||||
(label) bool_complex::@9
|
||||
(label) bool_complex::@return
|
||||
(byte) bool_complex::i
|
||||
(byte) bool_complex::i#1 reg byte y 16.5
|
||||
(byte) bool_complex::i#2 reg byte y 9.777777777777779
|
||||
(byte*) bool_complex::screen
|
||||
(const byte*) bool_complex::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1144
|
||||
(void()) bool_not()
|
||||
(byte~) bool_not::$3 reg byte a 11.0
|
||||
(label) bool_not::@1
|
||||
(label) bool_not::@2
|
||||
(label) bool_not::@3
|
||||
(label) bool_not::@4
|
||||
(label) bool_not::@7
|
||||
(label) bool_not::@return
|
||||
(byte) bool_not::i
|
||||
(byte) bool_not::i#1 reg byte x 16.5
|
||||
(byte) bool_not::i#2 reg byte x 11.0
|
||||
(byte*) bool_not::screen
|
||||
(const byte*) bool_not::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1104
|
||||
(void()) bool_or()
|
||||
(byte~) bool_or::$1 reg byte a 11.0
|
||||
(label) bool_or::@1
|
||||
(label) bool_or::@2
|
||||
(label) bool_or::@3
|
||||
(label) bool_or::@4
|
||||
(label) bool_or::@7
|
||||
(label) bool_or::@return
|
||||
(byte) bool_or::i
|
||||
(byte) bool_or::i#1 reg byte x 16.5
|
||||
(byte) bool_or::i#2 reg byte x 11.0
|
||||
(byte*) bool_or::screen
|
||||
(const byte*) bool_or::screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1064
|
||||
(void()) main()
|
||||
(byte~) main::$1 reg byte a 22.0
|
||||
(boolean~) main::$3 reg byte a 22.0
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@3
|
||||
(label) main::@4
|
||||
(label) main::@return
|
||||
(byte) main::i
|
||||
(byte) main::i#1 reg byte x 16.5
|
||||
(byte) main::i#2 reg byte x 8.25
|
||||
(boolean) main::o1
|
||||
(boolean) main::o1#0 o1 zp ZP_BOOL:2 7.333333333333333
|
||||
(boolean) main::o2
|
||||
(boolean) main::o2#0 reg byte a 22.0
|
||||
(byte*) screen
|
||||
(const byte*) screen#0 screen = ((byte*))(word/signed word/dword/signed dword) 1024
|
||||
|
||||
reg byte x [ main::i#2 main::i#1 ]
|
||||
zp ZP_BOOL:2 [ main::o1#0 ]
|
||||
reg byte a [ main::$1 ]
|
||||
reg byte a [ main::o2#0 ]
|
||||
reg byte a [ main::$3 ]
|
||||
reg byte y [ bool_complex::i#2 bool_complex::i#1 ]
|
||||
reg byte x [ bool_not::i#2 bool_not::i#1 ]
|
||||
reg byte x [ bool_or::i#2 bool_or::i#1 ]
|
||||
reg byte x [ bool_and::i#2 bool_and::i#1 ]
|
||||
reg byte x [ bool_complex::$3 ]
|
||||
reg byte a [ bool_complex::$7 ]
|
||||
reg byte a [ bool_not::$3 ]
|
||||
reg byte a [ bool_or::$1 ]
|
||||
reg byte a [ bool_and::$1 ]
|
||||
|
Loading…
Reference in New Issue
Block a user