aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorMeng-Ying Yang <garfield@dexon.org>2019-04-08 10:35:29 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:44:05 +0800
commita5f4e36e997232a16b4cb6b126bb2006a15fce3f (patch)
tree7f2aae30293757d011d5236cce59ebfc00deb6b0 /core
parentc07255382a10bdeaf7d5d2411e9c7c4cdc937694 (diff)
downloaddexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar
dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar.gz
dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar.bz2
dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar.lz
dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar.xz
dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.tar.zst
dexon-a5f4e36e997232a16b4cb6b126bb2006a15fce3f.zip
core: vm: sqlvm: add opNeg
Add `opNeg` supports operand negative.
Diffstat (limited to 'core')
-rw-r--r--core/vm/sqlvm/runtime/instructions.go50
-rw-r--r--core/vm/sqlvm/runtime/instructions_op_test.go116
-rw-r--r--core/vm/sqlvm/runtime/instructions_tmpl_data.go80
-rw-r--r--core/vm/sqlvm/runtime/jumptable.go1
-rw-r--r--core/vm/sqlvm/runtime/opcodes.go1
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.