From 1509f39154e9056654181c021b4be36ccce7aacc Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 30 Jun 2026 11:22:35 +0200 Subject: [PATCH] Implemented unsigned comparison --- lib/mem/raw_unix.q | 2 +- src/arm/Jump.go | 28 +++++++++++++++++++---- src/arm/Jump_test.go | 28 +++++++++++++++++++++-- src/arm/Set.go | 28 +++++++++++++++++++---- src/arm/Set_test.go | 24 ++++++++++++++++++-- src/arm/condition.go | 4 ++-- src/asm/compilerARM.go | 24 ++++++++++++++++---- src/asm/compilerX86.go | 34 +++++++++++++++++++++++----- src/codegen/jumpIfFalse.go | 12 ++++++++-- src/codegen/jumpIfTrue.go | 15 +------------ src/core/evaluateBinary.go | 13 +++++++++++ src/core/lintBinaryOp.go | 16 +++++++------- src/expression/operator.go | 2 +- src/token/Kind.go | 12 ++++++---- src/verbose/ASM.go | 44 +++++++++++++++++++++++++++---------- src/x86/Jump.go | 24 ++++++++++++++++++-- src/x86/Jump_test.go | 8 +++++-- src/x86/Set.go | 28 +++++++++++++++++++---- src/x86/Set_test.go | 24 ++++++++++++++++++-- tests/tests_test.go | 1 + tests/unsigned-comparison.q | 10 +++++++++ 21 files changed, 306 insertions(+), 75 deletions(-) create mode 100644 tests/unsigned-comparison.q diff --git a/lib/mem/raw_unix.q b/lib/mem/raw_unix.q index 834c3bf..f7d1d49 100644 --- a/lib/mem/raw_unix.q +++ b/lib/mem/raw_unix.q @@ -3,7 +3,7 @@ import run rawAlloc(length uint) -> *uint8 { x := mmap(0, length, read|write, private|anonymous, -1, 0) - if x < 0x1000 { + if (x as int) < 0x1000 { run.crash() } diff --git a/src/arm/Jump.go b/src/arm/Jump.go index cfb2573..d5760ed 100644 --- a/src/arm/Jump.go +++ b/src/arm/Jump.go @@ -24,8 +24,8 @@ func JumpIfGreater(offset int) (code uint32, encodable bool) { return branchCond(GT, offset) } -// JumpIfGreaterOrEqual jumps if the result was greater or equal. -func JumpIfGreaterOrEqual(offset int) (code uint32, encodable bool) { +// JumpIfGreaterEqual jumps if the result was greater or equal. +func JumpIfGreaterEqual(offset int) (code uint32, encodable bool) { return branchCond(GE, offset) } @@ -34,11 +34,31 @@ func JumpIfLess(offset int) (code uint32, encodable bool) { return branchCond(LT, offset) } -// JumpIfLessOrEqual jumps if the result was less or equal. -func JumpIfLessOrEqual(offset int) (code uint32, encodable bool) { +// JumpIfLessEqual jumps if the result was less or equal. +func JumpIfLessEqual(offset int) (code uint32, encodable bool) { return branchCond(LE, offset) } +// JumpIfUnsignedGreater jumps if the result was greater using unsigned comparison. +func JumpIfUnsignedGreater(offset int) (code uint32, encodable bool) { + return branchCond(HI, offset) +} + +// JumpIfUnsignedGreaterEqual jumps if the result was greater or equal using unsigned comparison. +func JumpIfUnsignedGreaterEqual(offset int) (code uint32, encodable bool) { + return branchCond(HS, offset) +} + +// JumpIfUnsignedLess jumps if the result was less using unsigned comparison. +func JumpIfUnsignedLess(offset int) (code uint32, encodable bool) { + return branchCond(LO, offset) +} + +// JumpIfUnsignedLessEqual jumps if the result was less or equal using unsigned comparison. +func JumpIfUnsignedLessEqual(offset int) (code uint32, encodable bool) { + return branchCond(LS, offset) +} + // branchCond performs a conditional branch to the new 19 bit offset multiplied by 4. func branchCond(cond condition, offset int) (code uint32, encodable bool) { if offset < -262144 || offset > 262143 { diff --git a/src/arm/Jump_test.go b/src/arm/Jump_test.go index 64cfe8a..e51a296 100644 --- a/src/arm/Jump_test.go +++ b/src/arm/Jump_test.go @@ -40,6 +40,22 @@ func TestJump(t *testing.T) { {6, 0, 0x5400000D}, {6, 1, 0x5400002D}, {6, -1, 0x54FFFFED}, + + {7, 0, 0x54000008}, + {7, 1, 0x54000028}, + {7, -1, 0x54FFFFE8}, + + {8, 0, 0x54000002}, + {8, 1, 0x54000022}, + {8, -1, 0x54FFFFE2}, + + {9, 0, 0x54000003}, + {9, 1, 0x54000023}, + {9, -1, 0x54FFFFE3}, + + {10, 0, 0x54000009}, + {10, 1, 0x54000029}, + {10, -1, 0x54FFFFE9}, } for _, pattern := range usagePatterns { @@ -60,11 +76,19 @@ func TestJump(t *testing.T) { case 3: code, encodable = arm.JumpIfGreater(pattern.Offset) case 4: - code, encodable = arm.JumpIfGreaterOrEqual(pattern.Offset) + code, encodable = arm.JumpIfGreaterEqual(pattern.Offset) case 5: code, encodable = arm.JumpIfLess(pattern.Offset) case 6: - code, encodable = arm.JumpIfLessOrEqual(pattern.Offset) + code, encodable = arm.JumpIfLessEqual(pattern.Offset) + case 7: + code, encodable = arm.JumpIfUnsignedGreater(pattern.Offset) + case 8: + code, encodable = arm.JumpIfUnsignedGreaterEqual(pattern.Offset) + case 9: + code, encodable = arm.JumpIfUnsignedLess(pattern.Offset) + case 10: + code, encodable = arm.JumpIfUnsignedLessEqual(pattern.Offset) } assert.Equal(t, code, pattern.Code) diff --git a/src/arm/Set.go b/src/arm/Set.go index ada7260..14bc6db 100644 --- a/src/arm/Set.go +++ b/src/arm/Set.go @@ -17,8 +17,8 @@ func SetIfGreater(destination cpu.Register) uint32 { return cset(GT, destination) } -// SetIfGreaterOrEqual sets the register to 1 if the result was greater or equal, otherwise to 0. -func SetIfGreaterOrEqual(destination cpu.Register) uint32 { +// SetIfGreaterEqual sets the register to 1 if the result was greater or equal, otherwise to 0. +func SetIfGreaterEqual(destination cpu.Register) uint32 { return cset(GE, destination) } @@ -27,11 +27,31 @@ func SetIfLess(destination cpu.Register) uint32 { return cset(LT, destination) } -// SetIfLessOrEqual sets the register to 1 if the result was less or equal, otherwise to 0. -func SetIfLessOrEqual(destination cpu.Register) uint32 { +// SetIfLessEqual sets the register to 1 if the result was less or equal, otherwise to 0. +func SetIfLessEqual(destination cpu.Register) uint32 { return cset(LE, destination) } +// SetIfUnsignedGreater sets the register to 1 if the result was greater using unsigned comparison, otherwise to 0. +func SetIfUnsignedGreater(destination cpu.Register) uint32 { + return cset(HI, destination) +} + +// SetIfUnsignedGreaterEqual sets the register to 1 if the result was greater or equal using unsigned comparison, otherwise to 0. +func SetIfUnsignedGreaterEqual(destination cpu.Register) uint32 { + return cset(HS, destination) +} + +// SetIfUnsignedLess sets the register to 1 if the result was less using unsigned comparison, otherwise to 0. +func SetIfUnsignedLess(destination cpu.Register) uint32 { + return cset(LO, destination) +} + +// SetIfUnsignedLessEqual sets the register to 1 if the result was less or equal using unsigned comparison, otherwise to 0. +func SetIfUnsignedLessEqual(destination cpu.Register) uint32 { + return cset(LS, destination) +} + // cset encodes a conditional set instruction. func cset(cond condition, destination cpu.Register) uint32 { return 0b10011010100<<21 | uint32(cond^1)<<12 | 1<<10 | reg3(destination, 0b11111, 0b11111) diff --git a/src/arm/Set_test.go b/src/arm/Set_test.go index 5e25ec3..1e91fff 100644 --- a/src/arm/Set_test.go +++ b/src/arm/Set_test.go @@ -26,6 +26,14 @@ func TestSet(t *testing.T) { {arm.X1, 5, 0x9A9FA7E1}, {arm.X0, 6, 0x9A9FC7E0}, {arm.X1, 6, 0x9A9FC7E1}, + {arm.X0, 7, 0x9A9F97E0}, + {arm.X1, 7, 0x9A9F97E1}, + {arm.X0, 8, 0x9A9F37E0}, + {arm.X1, 8, 0x9A9F37E1}, + {arm.X0, 9, 0x9A9F27E0}, + {arm.X1, 9, 0x9A9F27E1}, + {arm.X0, 10, 0x9A9F87E0}, + {arm.X1, 10, 0x9A9F87E1}, } for _, pattern := range usagePatterns { @@ -43,13 +51,25 @@ func TestSet(t *testing.T) { code = arm.SetIfGreater(pattern.Destination) case 4: t.Logf("cset %s, ge", pattern.Destination) - code = arm.SetIfGreaterOrEqual(pattern.Destination) + code = arm.SetIfGreaterEqual(pattern.Destination) case 5: t.Logf("cset %s, lt", pattern.Destination) code = arm.SetIfLess(pattern.Destination) case 6: t.Logf("cset %s, le", pattern.Destination) - code = arm.SetIfLessOrEqual(pattern.Destination) + code = arm.SetIfLessEqual(pattern.Destination) + case 7: + t.Logf("cset %s, hi", pattern.Destination) + code = arm.SetIfUnsignedGreater(pattern.Destination) + case 8: + t.Logf("cset %s, hs", pattern.Destination) + code = arm.SetIfUnsignedGreaterEqual(pattern.Destination) + case 9: + t.Logf("cset %s, lo", pattern.Destination) + code = arm.SetIfUnsignedLess(pattern.Destination) + case 10: + t.Logf("cset %s, ls", pattern.Destination) + code = arm.SetIfUnsignedLessEqual(pattern.Destination) } assert.Equal(t, code, pattern.Code) diff --git a/src/arm/condition.go b/src/arm/condition.go index 364c8fd..573e6ea 100644 --- a/src/arm/condition.go +++ b/src/arm/condition.go @@ -5,8 +5,8 @@ type condition uint8 const ( EQ condition = iota NE - CS - CC + HS // CS + LO // CC MI PL VS diff --git a/src/asm/compilerARM.go b/src/asm/compilerARM.go index 55aca02..889e5f5 100644 --- a/src/asm/compilerARM.go +++ b/src/asm/compilerARM.go @@ -101,11 +101,19 @@ func (c *compilerARM) Compile(instr Instruction) { case token.Greater: c.append(arm.SetIfGreater(instr.Destination)) case token.GreaterEqual: - c.append(arm.SetIfGreaterOrEqual(instr.Destination)) + c.append(arm.SetIfGreaterEqual(instr.Destination)) case token.Less: c.append(arm.SetIfLess(instr.Destination)) case token.LessEqual: - c.append(arm.SetIfLessOrEqual(instr.Destination)) + c.append(arm.SetIfLessEqual(instr.Destination)) + case token.UnsignedGreater: + c.append(arm.SetIfUnsignedGreater(instr.Destination)) + case token.UnsignedGreaterEqual: + c.append(arm.SetIfUnsignedGreaterEqual(instr.Destination)) + case token.UnsignedLess: + c.append(arm.SetIfUnsignedLess(instr.Destination)) + case token.UnsignedLessEqual: + c.append(arm.SetIfUnsignedLessEqual(instr.Destination)) default: panic("unknown condition") } @@ -146,11 +154,19 @@ func (c *compilerARM) Compile(instr Instruction) { case token.Greater: jump, encodable = arm.JumpIfGreater(offset) case token.GreaterEqual: - jump, encodable = arm.JumpIfGreaterOrEqual(offset) + jump, encodable = arm.JumpIfGreaterEqual(offset) case token.Less: jump, encodable = arm.JumpIfLess(offset) case token.LessEqual: - jump, encodable = arm.JumpIfLessOrEqual(offset) + jump, encodable = arm.JumpIfLessEqual(offset) + case token.UnsignedGreater: + jump, encodable = arm.JumpIfUnsignedGreater(offset) + case token.UnsignedGreaterEqual: + jump, encodable = arm.JumpIfUnsignedGreaterEqual(offset) + case token.UnsignedLess: + jump, encodable = arm.JumpIfUnsignedLess(offset) + case token.UnsignedLessEqual: + jump, encodable = arm.JumpIfUnsignedLessEqual(offset) default: jump, encodable = arm.Jump(offset) } diff --git a/src/asm/compilerX86.go b/src/asm/compilerX86.go index a6cc228..9575082 100644 --- a/src/asm/compilerX86.go +++ b/src/asm/compilerX86.go @@ -100,11 +100,19 @@ func (c *compilerX86) Compile(instr Instruction) { case token.Greater: c.code = x86.SetIfGreater(c.code, instr.Destination) case token.GreaterEqual: - c.code = x86.SetIfGreaterOrEqual(c.code, instr.Destination) + c.code = x86.SetIfGreaterEqual(c.code, instr.Destination) case token.Less: c.code = x86.SetIfLess(c.code, instr.Destination) case token.LessEqual: - c.code = x86.SetIfLessOrEqual(c.code, instr.Destination) + c.code = x86.SetIfLessEqual(c.code, instr.Destination) + case token.UnsignedGreater: + c.code = x86.SetIfUnsignedGreater(c.code, instr.Destination) + case token.UnsignedGreaterEqual: + c.code = x86.SetIfUnsignedGreaterEqual(c.code, instr.Destination) + case token.UnsignedLess: + c.code = x86.SetIfUnsignedLess(c.code, instr.Destination) + case token.UnsignedLessEqual: + c.code = x86.SetIfUnsignedLessEqual(c.code, instr.Destination) default: panic("unknown condition") } @@ -147,11 +155,19 @@ func (c *compilerX86) Compile(instr Instruction) { case token.Greater: c.code = x86.Jump8IfGreater(c.code, 0x00) case token.GreaterEqual: - c.code = x86.Jump8IfGreaterOrEqual(c.code, 0x00) + c.code = x86.Jump8IfGreaterEqual(c.code, 0x00) case token.Less: c.code = x86.Jump8IfLess(c.code, 0x00) case token.LessEqual: - c.code = x86.Jump8IfLessOrEqual(c.code, 0x00) + c.code = x86.Jump8IfLessEqual(c.code, 0x00) + case token.UnsignedGreater: + c.code = x86.Jump8IfUnsignedGreater(c.code, 0x00) + case token.UnsignedGreaterEqual: + c.code = x86.Jump8IfUnsignedGreaterEqual(c.code, 0x00) + case token.UnsignedLess: + c.code = x86.Jump8IfUnsignedLess(c.code, 0x00) + case token.UnsignedLessEqual: + c.code = x86.Jump8IfUnsignedLessEqual(c.code, 0x00) default: c.code = x86.Jump8(c.code, 0x00) } @@ -171,7 +187,7 @@ func (c *compilerX86) Compile(instr Instruction) { offset := address - patch.end switch code[0] { - case 0x74, 0x75, 0x7C, 0x7D, 0x7E, 0x7F, 0xEB: + case 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x7C, 0x7D, 0x7E, 0x7F, 0xEB: if cpu.SizeInt(offset) == 1 { code[1] = byte(offset) return code @@ -180,10 +196,18 @@ func (c *compilerX86) Compile(instr Instruction) { var jump []byte switch code[0] { + case 0x72: // JB + jump = []byte{0x0F, 0x82} + case 0x73: // JAE + jump = []byte{0x0F, 0x83} case 0x74: // JE jump = []byte{0x0F, 0x84} case 0x75: // JNE jump = []byte{0x0F, 0x85} + case 0x76: // JBE + jump = []byte{0x0F, 0x86} + case 0x77: // JA + jump = []byte{0x0F, 0x87} case 0x7C: // JL jump = []byte{0x0F, 0x8C} case 0x7D: // JGE diff --git a/src/codegen/jumpIfFalse.go b/src/codegen/jumpIfFalse.go index ac03d2f..6612db0 100644 --- a/src/codegen/jumpIfFalse.go +++ b/src/codegen/jumpIfFalse.go @@ -14,11 +14,19 @@ func (f *Function) jumpIfFalse(operator token.Kind, label string) { f.Assembler.Append(&asm.Jump{Label: label, Condition: token.Equal}) case token.Greater: f.Assembler.Append(&asm.Jump{Label: label, Condition: token.LessEqual}) - case token.Less: - f.Assembler.Append(&asm.Jump{Label: label, Condition: token.GreaterEqual}) case token.GreaterEqual: f.Assembler.Append(&asm.Jump{Label: label, Condition: token.Less}) + case token.Less: + f.Assembler.Append(&asm.Jump{Label: label, Condition: token.GreaterEqual}) case token.LessEqual: f.Assembler.Append(&asm.Jump{Label: label, Condition: token.Greater}) + case token.UnsignedGreater: + f.Assembler.Append(&asm.Jump{Label: label, Condition: token.UnsignedLessEqual}) + case token.UnsignedGreaterEqual: + f.Assembler.Append(&asm.Jump{Label: label, Condition: token.UnsignedLess}) + case token.UnsignedLess: + f.Assembler.Append(&asm.Jump{Label: label, Condition: token.UnsignedGreaterEqual}) + case token.UnsignedLessEqual: + f.Assembler.Append(&asm.Jump{Label: label, Condition: token.UnsignedGreater}) } } \ No newline at end of file diff --git a/src/codegen/jumpIfTrue.go b/src/codegen/jumpIfTrue.go index d72a1ff..e5268a6 100644 --- a/src/codegen/jumpIfTrue.go +++ b/src/codegen/jumpIfTrue.go @@ -7,18 +7,5 @@ import ( // jumpIfTrue jumps to the label if the previous comparison was true. func (f *Function) jumpIfTrue(operator token.Kind, label string) { - switch operator { - case token.Equal: - f.Assembler.Append(&asm.Jump{Label: label, Condition: token.Equal}) - case token.NotEqual: - f.Assembler.Append(&asm.Jump{Label: label, Condition: token.NotEqual}) - case token.Greater: - f.Assembler.Append(&asm.Jump{Label: label, Condition: token.Greater}) - case token.Less: - f.Assembler.Append(&asm.Jump{Label: label, Condition: token.Less}) - case token.GreaterEqual: - f.Assembler.Append(&asm.Jump{Label: label, Condition: token.GreaterEqual}) - case token.LessEqual: - f.Assembler.Append(&asm.Jump{Label: label, Condition: token.LessEqual}) - } + f.Assembler.Append(&asm.Jump{Label: label, Condition: operator}) } \ No newline at end of file diff --git a/src/core/evaluateBinary.go b/src/core/evaluateBinary.go index 8b80679..4333b53 100644 --- a/src/core/evaluateBinary.go +++ b/src/core/evaluateBinary.go @@ -76,6 +76,19 @@ func (f *Function) evaluateBinary(expr *expression.Expression) (ssa.Value, error } if v.Op.IsComparison() { + if types.IsUnsigned(leftValue.Type()) || types.IsUnsigned(rightValue.Type()) { + switch v.Op { + case token.Greater: + v.Op = token.UnsignedGreater + case token.GreaterEqual: + v.Op = token.UnsignedGreaterEqual + case token.Less: + v.Op = token.UnsignedLess + case token.LessEqual: + v.Op = token.UnsignedLessEqual + } + } + f.Block().Append(v) return v, nil } diff --git a/src/core/lintBinaryOp.go b/src/core/lintBinaryOp.go index 4e903e6..0ac3963 100644 --- a/src/core/lintBinaryOp.go +++ b/src/core/lintBinaryOp.go @@ -122,17 +122,17 @@ func (f *Function) lintBinaryOp(binOp *ssa.BinaryOp) error { switch { case rightInt.Int == 0: switch binOp.Op { - case token.Less: + case token.UnsignedLess: return errors.New(AlwaysFalse, f.File, binOp.Source) - case token.GreaterEqual: + case token.UnsignedGreaterEqual: return errors.New(AlwaysTrue, f.File, binOp.Source) } case rightInt.Int < 0 && strings.HasPrefix(rightInt.StringFrom(f.File.Bytes), "-"): switch binOp.Op { - case token.Equal, token.LessEqual, token.Less: + case token.Equal, token.UnsignedLessEqual, token.UnsignedLess: return errors.New(AlwaysFalse, f.File, binOp.Source) - case token.NotEqual, token.GreaterEqual, token.Greater: + case token.NotEqual, token.UnsignedGreaterEqual, token.UnsignedGreater: return errors.New(AlwaysTrue, f.File, binOp.Source) } } @@ -146,17 +146,17 @@ func (f *Function) lintBinaryOp(binOp *ssa.BinaryOp) error { switch { case leftInt.Int == 0: switch binOp.Op { - case token.Greater: + case token.UnsignedGreater: return errors.New(AlwaysFalse, f.File, binOp.Source) - case token.LessEqual: + case token.UnsignedLessEqual: return errors.New(AlwaysTrue, f.File, binOp.Source) } case leftInt.Int < 0 && strings.HasPrefix(leftInt.StringFrom(f.File.Bytes), "-"): switch binOp.Op { - case token.Equal, token.GreaterEqual, token.Greater: + case token.Equal, token.UnsignedGreaterEqual, token.UnsignedGreater: return errors.New(AlwaysFalse, f.File, binOp.Source) - case token.NotEqual, token.LessEqual, token.Less: + case token.NotEqual, token.UnsignedLessEqual, token.UnsignedLess: return errors.New(AlwaysTrue, f.File, binOp.Source) } } diff --git a/src/expression/operator.go b/src/expression/operator.go index 173fbda..8a64fa5 100644 --- a/src/expression/operator.go +++ b/src/expression/operator.go @@ -12,7 +12,7 @@ type operator struct { // Operators defines the Operators used in the language. // The number corresponds to the operator priority and can not be zero. -var Operators = [64]operator{ +var Operators = [256]operator{ token.Dot: {8, 2}, token.Call: {8, 1}, token.Array: {8, 2}, diff --git a/src/token/Kind.go b/src/token/Kind.go index a7e6837..05471ce 100644 --- a/src/token/Kind.go +++ b/src/token/Kind.go @@ -62,6 +62,10 @@ const ( Greater // > LessEqual // <= GreaterEqual // >= + UnsignedLess // unsigned < + UnsignedGreater // unsigned > + UnsignedLessEqual // unsigned <= + UnsignedGreaterEqual // unsigned >= ___END_COMPARISONS___ // ___UNARY___ // Not // ! (unary) @@ -196,13 +200,13 @@ func (k Kind) String() string { return "^" case Or: return "|" - case Greater: + case Greater, UnsignedGreater: return ">" - case Less: + case Less, UnsignedLess: return "<" - case GreaterEqual: + case GreaterEqual, UnsignedGreaterEqual: return ">=" - case LessEqual: + case LessEqual, UnsignedLessEqual: return "<=" case Equal: return "==" diff --git a/src/verbose/ASM.go b/src/verbose/ASM.go index 9f33a91..a9abd8c 100644 --- a/src/verbose/ASM.go +++ b/src/verbose/ASM.go @@ -90,16 +90,26 @@ func printAssembly(f *core.Function) { switch instr.Condition { case token.Equal: mnemonic.Print(" set if == ") + case token.NotEqual: + mnemonic.Print(" set if != ") case token.Greater: - mnemonic.Print(" set if > ") + mnemonic.Print(" set if.s > ") case token.GreaterEqual: - mnemonic.Print(" set if >= ") + mnemonic.Print(" set if.s >= ") case token.Less: - mnemonic.Print(" set if < ") + mnemonic.Print(" set if.s < ") case token.LessEqual: - mnemonic.Print(" set if <= ") - case token.NotEqual: - mnemonic.Print(" set if != ") + mnemonic.Print(" set if.s <= ") + case token.UnsignedGreater: + mnemonic.Print(" set if.u > ") + case token.UnsignedGreaterEqual: + mnemonic.Print(" set if.u >= ") + case token.UnsignedLess: + mnemonic.Print(" set if.u < ") + case token.UnsignedLessEqual: + mnemonic.Print(" set if.u <= ") + default: + ansi.Red.Print(" set: unknown condition: " + instr.Condition.String() + " ") } register.Print(instr.Destination) @@ -121,18 +131,28 @@ func printAssembly(f *core.Function) { switch instr.Condition { case token.Equal: mnemonic.Print(" jump if == ") + case token.NotEqual: + mnemonic.Print(" jump if != ") case token.Greater: - mnemonic.Print(" jump if > ") + mnemonic.Print(" jump if.s > ") case token.GreaterEqual: - mnemonic.Print(" jump if >= ") + mnemonic.Print(" jump if.s >= ") case token.Less: - mnemonic.Print(" jump if < ") + mnemonic.Print(" jump if.s < ") case token.LessEqual: - mnemonic.Print(" jump if <= ") - case token.NotEqual: - mnemonic.Print(" jump if != ") + mnemonic.Print(" jump if.s <= ") + case token.UnsignedGreater: + mnemonic.Print(" jump if.u > ") + case token.UnsignedGreaterEqual: + mnemonic.Print(" jump if.u >= ") + case token.UnsignedLess: + mnemonic.Print(" jump if.u < ") + case token.UnsignedLessEqual: + mnemonic.Print(" jump if.u <= ") case token.Invalid: mnemonic.Print(" jump ") + default: + ansi.Red.Print(" jump: unknown condition: " + instr.Condition.String() + " ") } label.Print(ssa.CleanLabel(instr.Label)) diff --git a/src/x86/Jump.go b/src/x86/Jump.go index 58a58b9..5191677 100644 --- a/src/x86/Jump.go +++ b/src/x86/Jump.go @@ -22,7 +22,7 @@ func Jump8IfGreater(code []byte, offset int8) []byte { } // JumpIfGreaterOrEqual jumps if the result was greater or equal. -func Jump8IfGreaterOrEqual(code []byte, offset int8) []byte { +func Jump8IfGreaterEqual(code []byte, offset int8) []byte { return append(code, 0x7D, byte(offset)) } @@ -32,6 +32,26 @@ func Jump8IfLess(code []byte, offset int8) []byte { } // JumpIfLessOrEqual jumps if the result was less or equal. -func Jump8IfLessOrEqual(code []byte, offset int8) []byte { +func Jump8IfLessEqual(code []byte, offset int8) []byte { return append(code, 0x7E, byte(offset)) +} + +// Jump8IfUnsignedGreater jumps if the result was greater using unsigned comparison. +func Jump8IfUnsignedGreater(code []byte, offset int8) []byte { + return append(code, 0x77, byte(offset)) +} + +// Jump8IfUnsignedGreaterEqual jumps if the result was greater or equal using unsigned comparison. +func Jump8IfUnsignedGreaterEqual(code []byte, offset int8) []byte { + return append(code, 0x73, byte(offset)) +} + +// Jump8IfUnsignedLess jumps if the result was less using unsigned comparison. +func Jump8IfUnsignedLess(code []byte, offset int8) []byte { + return append(code, 0x72, byte(offset)) +} + +// Jump8IfUnsignedLessEqual jumps if the result was less or equal using unsigned comparison. +func Jump8IfUnsignedLessEqual(code []byte, offset int8) []byte { + return append(code, 0x76, byte(offset)) } \ No newline at end of file diff --git a/src/x86/Jump_test.go b/src/x86/Jump_test.go index 8bb81b1..d47d9e7 100644 --- a/src/x86/Jump_test.go +++ b/src/x86/Jump_test.go @@ -31,10 +31,14 @@ func TestJump(t *testing.T) { } func TestConditionalJump(t *testing.T) { + assert.DeepEqual(t, x86.Jump8IfUnsignedLess(nil, 1), []byte{0x72, 0x01}) + assert.DeepEqual(t, x86.Jump8IfUnsignedGreaterEqual(nil, 1), []byte{0x73, 0x01}) assert.DeepEqual(t, x86.Jump8IfEqual(nil, 1), []byte{0x74, 0x01}) assert.DeepEqual(t, x86.Jump8IfNotEqual(nil, 1), []byte{0x75, 0x01}) + assert.DeepEqual(t, x86.Jump8IfUnsignedLessEqual(nil, 1), []byte{0x76, 0x01}) + assert.DeepEqual(t, x86.Jump8IfUnsignedGreater(nil, 1), []byte{0x77, 0x01}) assert.DeepEqual(t, x86.Jump8IfLess(nil, 1), []byte{0x7C, 0x01}) - assert.DeepEqual(t, x86.Jump8IfGreaterOrEqual(nil, 1), []byte{0x7D, 0x01}) - assert.DeepEqual(t, x86.Jump8IfLessOrEqual(nil, 1), []byte{0x7E, 0x01}) + assert.DeepEqual(t, x86.Jump8IfGreaterEqual(nil, 1), []byte{0x7D, 0x01}) + assert.DeepEqual(t, x86.Jump8IfLessEqual(nil, 1), []byte{0x7E, 0x01}) assert.DeepEqual(t, x86.Jump8IfGreater(nil, 1), []byte{0x7F, 0x01}) } \ No newline at end of file diff --git a/src/x86/Set.go b/src/x86/Set.go index 18d4d32..9217a46 100644 --- a/src/x86/Set.go +++ b/src/x86/Set.go @@ -17,8 +17,8 @@ func SetIfGreater(code []byte, destination cpu.Register) []byte { return append(code, 0x0F, 0x9F, ModRM(AddressDirect, 0, byte(destination))) } -// SetIfGreaterOrEqual sets the register to 1 if the result was greater or equal, otherwise to 0. -func SetIfGreaterOrEqual(code []byte, destination cpu.Register) []byte { +// SetIfGreaterEqual sets the register to 1 if the result was greater or equal, otherwise to 0. +func SetIfGreaterEqual(code []byte, destination cpu.Register) []byte { return append(code, 0x0F, 0x9D, ModRM(AddressDirect, 0, byte(destination))) } @@ -27,7 +27,27 @@ func SetIfLess(code []byte, destination cpu.Register) []byte { return append(code, 0x0F, 0x9C, ModRM(AddressDirect, 0, byte(destination))) } -// SetIfLessOrEqual sets the register to 1 if the result was less or equal, otherwise to 0. -func SetIfLessOrEqual(code []byte, destination cpu.Register) []byte { +// SetIfLessEqual sets the register to 1 if the result was less or equal, otherwise to 0. +func SetIfLessEqual(code []byte, destination cpu.Register) []byte { return append(code, 0x0F, 0x9E, ModRM(AddressDirect, 0, byte(destination))) +} + +// SetIfUnsignedGreater sets the register to 1 if the result was greater using unsigned comparison, otherwise to 0. +func SetIfUnsignedGreater(code []byte, destination cpu.Register) []byte { + return append(code, 0x0F, 0x97, ModRM(AddressDirect, 0, byte(destination))) +} + +// SetIfUnsignedGreaterEqual sets the register to 1 if the result was greater or equal using unsigned comparison, otherwise to 0. +func SetIfUnsignedGreaterEqual(code []byte, destination cpu.Register) []byte { + return append(code, 0x0F, 0x93, ModRM(AddressDirect, 0, byte(destination))) +} + +// SetIfUnsignedLess sets the register to 1 if the result was less using unsigned comparison, otherwise to 0. +func SetIfUnsignedLess(code []byte, destination cpu.Register) []byte { + return append(code, 0x0F, 0x92, ModRM(AddressDirect, 0, byte(destination))) +} + +// SetIfUnsignedLessEqual sets the register to 1 if the result was less or equal using unsigned comparison, otherwise to 0. +func SetIfUnsignedLessEqual(code []byte, destination cpu.Register) []byte { + return append(code, 0x0F, 0x96, ModRM(AddressDirect, 0, byte(destination))) } \ No newline at end of file diff --git a/src/x86/Set_test.go b/src/x86/Set_test.go index c6bd252..b0a06d6 100644 --- a/src/x86/Set_test.go +++ b/src/x86/Set_test.go @@ -26,6 +26,14 @@ func TestSet(t *testing.T) { {x86.R1, 5, []byte{0x0F, 0x9C, 0xC1}}, {x86.R0, 6, []byte{0x0F, 0x9E, 0xC0}}, {x86.R1, 6, []byte{0x0F, 0x9E, 0xC1}}, + {x86.R0, 7, []byte{0x0F, 0x97, 0xC0}}, + {x86.R1, 7, []byte{0x0F, 0x97, 0xC1}}, + {x86.R0, 8, []byte{0x0F, 0x93, 0xC0}}, + {x86.R1, 8, []byte{0x0F, 0x93, 0xC1}}, + {x86.R0, 9, []byte{0x0F, 0x92, 0xC0}}, + {x86.R1, 9, []byte{0x0F, 0x92, 0xC1}}, + {x86.R0, 10, []byte{0x0F, 0x96, 0xC0}}, + {x86.R1, 10, []byte{0x0F, 0x96, 0xC1}}, } for _, pattern := range usagePatterns { @@ -43,13 +51,25 @@ func TestSet(t *testing.T) { code = x86.SetIfGreater(nil, pattern.Register) case 4: t.Logf("setge %s", pattern.Register) - code = x86.SetIfGreaterOrEqual(nil, pattern.Register) + code = x86.SetIfGreaterEqual(nil, pattern.Register) case 5: t.Logf("setl %s", pattern.Register) code = x86.SetIfLess(nil, pattern.Register) case 6: t.Logf("setle %s", pattern.Register) - code = x86.SetIfLessOrEqual(nil, pattern.Register) + code = x86.SetIfLessEqual(nil, pattern.Register) + case 7: + t.Logf("seta %s", pattern.Register) + code = x86.SetIfUnsignedGreater(nil, pattern.Register) + case 8: + t.Logf("setae %s", pattern.Register) + code = x86.SetIfUnsignedGreaterEqual(nil, pattern.Register) + case 9: + t.Logf("setb %s", pattern.Register) + code = x86.SetIfUnsignedLess(nil, pattern.Register) + case 10: + t.Logf("setbe %s", pattern.Register) + code = x86.SetIfUnsignedLessEqual(nil, pattern.Register) } assert.DeepEqual(t, code, pattern.Code) diff --git a/tests/tests_test.go b/tests/tests_test.go index 498c63d..6f29ade 100644 --- a/tests/tests_test.go +++ b/tests/tests_test.go @@ -28,6 +28,7 @@ var tests = []run{ {"bitwise-or", nil, "", "", 0}, {"bitwise-xor", nil, "", "", 0}, {"unsigned", nil, "", "", 0}, + {"unsigned-comparison", nil, "", "", 0}, {"shift", nil, "", "", 0}, {"shift-register", nil, "", "", 0}, {"shift-sign", nil, "", "", 0}, diff --git a/tests/unsigned-comparison.q b/tests/unsigned-comparison.q new file mode 100644 index 0000000..124b0c9 --- /dev/null +++ b/tests/unsigned-comparison.q @@ -0,0 +1,10 @@ +main() { + a := 0x80 as uint8 + assert a > 0 + b := 0x8000 as uint16 + assert b > 0 + c := 0x80000000 as uint32 + assert c > 0 + d := 0x8000000000000000 as uint64 + assert d > 0 +} \ No newline at end of file -- 2.51.2