diff options
author | Meng-Ying Yang <garfield@dexon.org> | 2019-04-08 10:35:29 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-05-06 10:44:05 +0800 |
commit | a5f4e36e997232a16b4cb6b126bb2006a15fce3f (patch) | |
tree | 7f2aae30293757d011d5236cce59ebfc00deb6b0 | |
parent | c07255382a10bdeaf7d5d2411e9c7c4cdc937694 (diff) | |
download | dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar.gz dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar.zst dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.zip |
core: vm: sqlvm: add opNeg
Add `opNeg` supports operand negative.
-rw-r--r-- | core/vm/sqlvm/runtime/instructions.go | 50 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_op_test.go | 116 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/instructions_tmpl_data.go | 80 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/jumptable.go | 1 | ||||
-rw-r--r-- | core/vm/sqlvm/runtime/opcodes.go | 1 |
5 files changed, 248 insertions, 0 deletions
diff --git a/core/vm/sqlvm/runtime/instructions.go b/core/vm/sqlvm/runtime/instructions.go index 4b03b6494..5cd622180 100644 --- a/core/vm/sqlvm/runtime/instructions.go +++ b/core/vm/sqlvm/runtime/instructions.go @@ -366,6 +366,17 @@ func metaDynBytes(dType ast.DataType) bool { func metaAllDynBytes(op *Operand) bool { return metaAll(op, metaDynBytes) } +func metaSignedNumeric(dType ast.DataType) bool { + major, _ := ast.DecomposeDataType(dType) + if major == ast.DataTypeMajorInt || + major == ast.DataTypeMajorFixed { + return true + } + return false +} + +func metaAllSignedNumeric(op *Operand) bool { return metaAll(op, metaSignedNumeric) } + func flowCheck(ctx *common.Context, v decimal.Decimal, dType ast.DataType) (err error) { if !ctx.Opt.SafeMath { return @@ -1780,3 +1791,42 @@ func (t Tuple) concat(t2 Tuple) (t3 Tuple) { } return } + +func opNeg(ctx *common.Context, ops, registers []*Operand, output uint) (err error) { + if len(ops) != 1 { + err = se.ErrorCodeDataLengthNotMatch + return + } + op := ops[0] + + if !metaAllSignedNumeric(op) { + err = se.ErrorCodeInvalidDataType + return + } + + op2 := op.clone(true) + op2.Data = make([]Tuple, len(op.Data)) + + for i := 0; i < len(op.Data); i++ { + op2.Data[i], err = op.Data[i].neg(ctx, op2.Meta) + if err != nil { + return + } + } + + registers[output] = op2 + return +} + +func (t Tuple) neg(ctx *common.Context, meta []ast.DataType) (t2 Tuple, err error) { + t2 = make(Tuple, len(t)) + for i := 0; i < len(t); i++ { + t2[i] = &Raw{Value: t[i].Value.Neg()} + + err = flowCheck(ctx, t2[i].Value, meta[i]) + if err != nil { + return + } + } + return +} diff --git a/core/vm/sqlvm/runtime/instructions_op_test.go b/core/vm/sqlvm/runtime/instructions_op_test.go index 6c10a2e87..c01eb3bf2 100644 --- a/core/vm/sqlvm/runtime/instructions_op_test.go +++ b/core/vm/sqlvm/runtime/instructions_op_test.go @@ -1401,6 +1401,122 @@ func (s *instructionSuite) TestOpConcat() { s.run(testcases, opConcat) } +func (s *instructionSuite) TestOpNeg() { + testcases := []opTestcase{ + { + "Neg unary", + Instruction{ + Op: NEG, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(-1)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(-1)}, &Raw{Value: decimal.NewFromFloat(0)}, &Raw{Value: decimal.NewFromFloat(1)}}, + }, + ), + nil, + }, + { + "Overflow Neg", + Instruction{ + Op: NEG, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorInt, 0), + }, + []Tuple{ + {&Raw{Value: decimal.NewFromFloat(-128)}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{}, + []Tuple{}, + ), + errors.ErrorCodeOverflow, + }, + { + "Invalid Neg", + Instruction{ + Op: NEG, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abc-1")}, rawTrue}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{}, + []Tuple{}, + ), + errors.ErrorCodeInvalidDataType, + }, + { + "Invalid Neg", + Instruction{ + Op: NEG, + Input: []*Operand{ + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorBool, 0), + }, + []Tuple{ + {rawTrue}, + }, + ), + makeOperand( + false, + []ast.DataType{ + ast.ComposeDataType(ast.DataTypeMajorDynamicBytes, 0), + }, + []Tuple{ + {&Raw{Bytes: []byte("abc-1")}}, + }, + ), + }, + Output: 0, + }, + makeOperand( + false, + []ast.DataType{}, + []Tuple{}, + ), + errors.ErrorCodeDataLengthNotMatch, + }, + } + + s.run(testcases, opNeg) +} + func (s *instructionSuite) TestOpLt() { testcases := []opTestcase{ { diff --git a/core/vm/sqlvm/runtime/instructions_tmpl_data.go b/core/vm/sqlvm/runtime/instructions_tmpl_data.go index a55dab60a..e6cf97a9a 100644 --- a/core/vm/sqlvm/runtime/instructions_tmpl_data.go +++ b/core/vm/sqlvm/runtime/instructions_tmpl_data.go @@ -841,6 +841,86 @@ var testData = &tmplData{ }, // -- end of CONCAT { + TestName: "OpNeg", OpFunc: "opNeg", + Cases: []*tmplTestCase{ + { + Name: "Neg unary", + Error: "nil", OpCode: "NEG", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "Int", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Int", Minor: 0}, + }, + Data: []string{`{V: 1, V: 0, V: -1}`}, + }, + }, + Output: &tmplOp{ + Im: false, + Metas: []*tmplOpMeta{ + {Major: "Int", Minor: 0}, + {Major: "Int", Minor: 0}, + {Major: "Int", Minor: 0}, + }, + Data: []string{`{V: -1, V: 0, V: 1}`}, + }, + }, + { + Name: "Overflow Neg", + Error: "errors.ErrorCodeOverflow", OpCode: "NEG", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "Int", Minor: 0}, + }, + Data: []string{`{V: -128}`}, + }, + }, + Output: &tmplOp{}, + }, + { + Name: "Invalid Neg", + Error: "errors.ErrorCodeInvalidDataType", OpCode: "NEG", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + {Major: "Bool", Minor: 0}, + }, + Data: []string{`{B: "abc-1", T}`}, + }, + }, + Output: &tmplOp{}, + }, + { + Name: "Invalid Neg", + Error: "errors.ErrorCodeDataLengthNotMatch", OpCode: "NEG", + Inputs: []*tmplOp{ + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "Bool", Minor: 0}, + }, + Data: []string{`{T}`}, + }, + { + Im: false, + Metas: []*tmplOpMeta{ + {Major: "DynamicBytes", Minor: 0}, + }, + Data: []string{`{B: "abc-1"}`}, + }, + }, + Output: &tmplOp{}, + }, + }, + }, + // -- end of NEG + { TestName: "OpLt", OpFunc: "opLt", Cases: []*tmplTestCase{ { diff --git a/core/vm/sqlvm/runtime/jumptable.go b/core/vm/sqlvm/runtime/jumptable.go index f6cad57e7..ef1fc8841 100644 --- a/core/vm/sqlvm/runtime/jumptable.go +++ b/core/vm/sqlvm/runtime/jumptable.go @@ -8,6 +8,7 @@ var jumpTable = [256]OpFunction{ DIV: opDiv, MOD: opMod, CONCAT: opConcat, + NEG: opNeg, // 0x20 LT: opLt, diff --git a/core/vm/sqlvm/runtime/opcodes.go b/core/vm/sqlvm/runtime/opcodes.go index 12a4dfefb..5a0e5dd95 100644 --- a/core/vm/sqlvm/runtime/opcodes.go +++ b/core/vm/sqlvm/runtime/opcodes.go @@ -16,6 +16,7 @@ const ( DIV MOD CONCAT + NEG ) // 0x20 range - comparison ops. |