From 713f727d983ec2c0c8307a7dcafc270aeee900dd Mon Sep 17 00:00:00 2001 From: Paul Chaignon Date: Fri, 18 Oct 2019 14:45:31 +0200 Subject: prog, pkg/compiler: alignment for integer ranges Enables the syntax intN[start:end, alignment] for integer ranges. For instance, int32[0:10, 2] represents even 32-bit numbers between 0 and 10 included. With this change, two NEED tags in syscall descriptions can be addressed. Signed-off-by: Paul Chaignon --- pkg/compiler/consts_test.go | 3 ++- pkg/compiler/testdata/all.txt | 5 ++++ pkg/compiler/testdata/consts.txt | 2 +- pkg/compiler/testdata/errors.txt | 1 + pkg/compiler/testdata/errors2.txt | 7 ++++++ pkg/compiler/types.go | 50 ++++++++++++++++++++++++++++++++------- 6 files changed, 57 insertions(+), 11 deletions(-) (limited to 'pkg/compiler') diff --git a/pkg/compiler/consts_test.go b/pkg/compiler/consts_test.go index 37c2625d1..69810c877 100644 --- a/pkg/compiler/consts_test.go +++ b/pkg/compiler/consts_test.go @@ -37,7 +37,8 @@ func TestExtractConsts(t *testing.T) { "CONST6", "CONST7", "CONST8", "CONST9", "CONST10", "CONST11", "CONST12", "CONST13", "CONST14", "CONST15", "CONST16", "CONST17", "CONST18", "CONST19", "CONST20", - "CONST21", "CONST22", "CONST23", "CONST24", + "CONST21", "CONST22", "CONST23", "CONST24", "CONST25", + "CONST26", } sort.Strings(wantConsts) if !reflect.DeepEqual(info.Consts, wantConsts) { diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index 9bb2c3d16..82aad66f4 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -12,6 +12,8 @@ foo$7(a int8[-20:20]) foo$8(a ptr[in, strings]) foo$9(a ptr[out, ptr[in, string]]) foo$10(a ptr[out, buffer[in]]) +foo$11(a int64[1:100, 2]) +foo$12(a int64[0:-1, 0x1000]) resource r0[intptr] @@ -166,6 +168,9 @@ foo$void8(a ptr[in, void]) bitfield0 { f1 int8:1 f2 int8:2 + f3 int16:8[-255:0] + f4 int16:8[0:255] + f5 int64:64[-1:1] } foo$bitfield0(a ptr[in, bitfield0]) diff --git a/pkg/compiler/testdata/consts.txt b/pkg/compiler/testdata/consts.txt index ef248a1e0..29cdfb6a0 100644 --- a/pkg/compiler/testdata/consts.txt +++ b/pkg/compiler/testdata/consts.txt @@ -21,7 +21,7 @@ str { bar$BAZ(x vma[opt], y vma[CONST8], z vma[CONST9:CONST10]) bar$QUX(s ptr[in, string["foo", CONST11]], x ptr[in, csum[s, pseudo, CONST12, int16]]) -bar$FOO(x int8[8:CONST13], y int16be[CONST14:10], z intptr[CONST15:CONST16]) +bar$FOO(x int8[8:CONST13], y int16be[CONST14:10], z intptr[CONST15:CONST16], w int32[0:CONST25, CONST26]) type type0 const[CONST17, int8] type templ0[C] const[C, int8] diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt index a43cc55af..d7d80151a 100644 --- a/pkg/compiler/testdata/errors.txt +++ b/pkg/compiler/testdata/errors.txt @@ -122,6 +122,7 @@ foo$64(a ptr[in, flags[f1[int32], int32]]) ### flags argument has subargs foo$65(a int32, b len[1]) ### unexpected int 1 for len target argument of len type, expect identifier foo$66(a int32, b len[a:1]) ### unexpected int 1 after colon, expect identifier foo$67(x int32[1:2:3, opt]) ### unexpected ':' +foo$68(a int32[15, 2]) ### first argument of int32 needs to be a range opt { ### struct uses reserved name opt f1 int32 diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index db8f87e25..a2e1d682c 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -254,6 +254,13 @@ foo$512(a ptr[in, array[int8, -2:-1]]) ### bad size range [18446744073709551614: foo$513(a ptr[in, array[int8, -2:2]]) ### bad size range [18446744073709551614:2] foo$514(a vma[-2:2]) ### bad size range [18446744073709551614:2] foo$515(a ptr[in, proc[1, -10, int64]]) ### values starting from 1 with step 18446744073709551606 overflow base type for 32 procs +foo$516(a ptr[in, intptr[0:2, 1]]) ### bad int alignment 1 +foo$517(a intptr[0:0xffffffff, 0]) ### bad int alignment 0 +foo$518(a int64[1:100, -1]) ### int alignment 18446744073709551615 is too large for range [1:100] +foo$519(a int64[0:10, 512]) ### int alignment 512 is too large for range [0:10] +foo$520(a int8[0:16, 0xffff]) ### int alignment 65535 is too large for range [0:16] +foo$521(a int32[9:10, 8]) ### int alignment 8 is too large for range [9:10] +foo$522(a int8[0:-1, 1000]) ### int alignment 1000 is too large for range [0:255] type type500 proc[C1, 8, int8] ### values starting from 1 with step 8 overflow base type for 32 procs type type501 int8 ### unused type type501 diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index 928c15ba1..32fc36605 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -68,8 +68,11 @@ var typeInt = &typeDesc{ CanBeArgRet: canBeArg, CanBeTypedef: true, MaxColon: 1, - OptArgs: 1, - Args: []namedArg{{Name: "range", Type: typeArgIntRange}}, + OptArgs: 2, + Args: []namedArg{ + {Name: "range", Type: typeArgIntRange}, + {Name: "align", Type: typeArgIntAlign}, + }, CanBeResourceBase: func(comp *compiler, t *ast.Type) bool { // Big-endian resources can always be converted to non-big-endian, // since we will always revert bytes during copyout and during copyin, @@ -84,15 +87,42 @@ var typeInt = &typeDesc{ comp.error(args[0].Pos, "first argument of %v needs to be a range", t.Ident) } }, + CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { + if len(args) > 0 && len(args[0].Colon) != 0 { + begin := args[0].Value + end := args[0].Colon[0].Value + size, _ := comp.parseIntType(t.Ident) + size = size * 8 + if len(t.Colon) != 0 { + // Integer is bitfield. + size = t.Colon[0].Value + } + if len(args) > 1 && begin == 0 && int64(end) == -1 { + // intN[0:-1, align] is a special value for 'all possible values', + // but aligned. + end = 1< 1<<64-1<<32 { + comp.error(args[0].Pos, "bad int range [%v:%v]", begin, end) + return + } + if len(args) > 1 && args[1].Value != 0 && (end-begin)/args[1].Value == 0 { + comp.error(args[1].Pos, "int alignment %v is too large for range [%v:%v]", + args[1].Value, begin, end) + } + } + }, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { size, be := comp.parseIntType(t.Ident) - kind, rangeBegin, rangeEnd := prog.IntPlain, uint64(0), uint64(0) + kind, rangeBegin, rangeEnd, align := prog.IntPlain, uint64(0), uint64(0), uint64(0) if len(args) > 0 { rangeArg := args[0] kind, rangeBegin, rangeEnd = prog.IntRange, rangeArg.Value, rangeArg.Value if len(rangeArg.Colon) != 0 { rangeEnd = rangeArg.Colon[0].Value } + if len(args) > 1 { + align = args[1].Value + } } var bitLen uint64 if len(t.Colon) != 0 { @@ -104,6 +134,7 @@ var typeInt = &typeDesc{ Kind: kind, RangeBegin: rangeBegin, RangeEnd: rangeEnd, + Align: align, } }, } @@ -794,13 +825,14 @@ var typeArgInt = &typeArg{ var typeArgIntRange = &typeArg{ Kind: kindInt, MaxColon: 1, +} + +var typeArgIntAlign = &typeArg{ + Kind: kindInt, + MaxColon: 0, CheckConsts: func(comp *compiler, t *ast.Type) { - end := t.Value - if len(t.Colon) != 0 { - end = t.Colon[0].Value - } - if end-t.Value > 1<<64-1<<32 { - comp.error(t.Pos, "bad int range [%v:%v]", t.Value, end) + if t.Value <= 1 { + comp.error(t.Pos, "bad int alignment %v", t.Value) } }, } -- cgit mrf-deployment