@@ -38,7 +38,10 @@ import {
38
38
Expression ,
39
39
LiteralKind ,
40
40
StringLiteralExpression ,
41
- CallExpression
41
+ CallExpression ,
42
+ NodeKind ,
43
+ LiteralExpression ,
44
+ ArrayLiteralExpression
42
45
} from "./ast" ;
43
46
44
47
import {
@@ -581,6 +584,7 @@ export namespace BuiltinNames {
581
584
export const memory_grow = "~lib/memory/memory.grow" ;
582
585
export const memory_copy = "~lib/memory/memory.copy" ;
583
586
export const memory_fill = "~lib/memory/memory.fill" ;
587
+ export const memory_data = "~lib/memory/memory.data" ;
584
588
585
589
// std/typedarray.ts
586
590
export const Int8Array = "~lib/typedarray/Int8Array" ;
@@ -1970,37 +1974,21 @@ function builtin_load(ctx: BuiltinContext): ExpressionRef {
1970
1974
) ? contextualType : type ;
1971
1975
var arg0 = compiler . compileExpression ( operands [ 0 ] , compiler . options . usizeType , Constraints . CONV_IMPLICIT ) ;
1972
1976
var numOperands = operands . length ;
1973
- var immOffset = numOperands >= 2 ? evaluateImmediateOffset ( operands [ 1 ] , compiler ) : 0 ; // reports
1974
- if ( immOffset < 0 ) {
1975
- compiler . currentType = outType ;
1976
- return module . unreachable ( ) ;
1977
- }
1978
- var immAlign : i32 ;
1979
- var naturalAlign = type . byteSize ;
1980
- if ( numOperands == 3 ) {
1981
- immAlign = evaluateImmediateOffset ( operands [ 2 ] , compiler ) ;
1982
- if ( immAlign < 0 ) {
1977
+ var immOffset = 0 ;
1978
+ var immAlign = type . byteSize ;
1979
+ if ( numOperands >= 2 ) {
1980
+ immOffset = evaluateImmediateOffset ( operands [ 1 ] , compiler ) ; // reports
1981
+ if ( immOffset < 0 ) {
1983
1982
compiler . currentType = outType ;
1984
1983
return module . unreachable ( ) ;
1985
1984
}
1986
- if ( immAlign > naturalAlign ) {
1987
- compiler . error (
1988
- DiagnosticCode . _0_must_be_a_value_between_1_and_2_inclusive ,
1989
- operands [ 2 ] . range , "Alignment" , "0" , naturalAlign . toString ( )
1990
- ) ;
1991
- compiler . currentType = outType ;
1992
- return module . unreachable ( ) ;
1993
- }
1994
- if ( ! isPowerOf2 ( immAlign ) ) {
1995
- compiler . error (
1996
- DiagnosticCode . _0_must_be_a_power_of_two ,
1997
- operands [ 2 ] . range , "Alignment"
1998
- ) ;
1999
- compiler . currentType = outType ;
2000
- return module . unreachable ( ) ;
1985
+ if ( numOperands == 3 ) {
1986
+ immAlign = evaluateImmediateAlign ( operands [ 2 ] , immAlign , compiler ) ; // reports
1987
+ if ( immAlign < 0 ) {
1988
+ compiler . currentType = outType ;
1989
+ return module . unreachable ( ) ;
1990
+ }
2001
1991
}
2002
- } else {
2003
- immAlign = naturalAlign ;
2004
1992
}
2005
1993
compiler . currentType = outType ;
2006
1994
return module . load (
@@ -2024,6 +2012,7 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
2024
2012
checkArgsOptional ( ctx , 2 , 4 )
2025
2013
) return module . unreachable ( ) ;
2026
2014
var operands = ctx . operands ;
2015
+ var numOperands = operands . length ;
2027
2016
var typeArguments = ctx . typeArguments ;
2028
2017
var contextualType = ctx . contextualType ;
2029
2018
var type = typeArguments ! [ 0 ] ;
@@ -2055,37 +2044,21 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
2055
2044
) ;
2056
2045
inType = type ;
2057
2046
}
2058
- var immOffset = operands . length >= 3 ? evaluateImmediateOffset ( operands [ 2 ] , compiler ) : 0 ; // reports
2059
- if ( immOffset < 0 ) {
2060
- compiler . currentType = Type . void ;
2061
- return module . unreachable ( ) ;
2062
- }
2063
- var immAlign : i32 ;
2064
- var naturalAlign = type . byteSize ;
2065
- if ( operands . length == 4 ) {
2066
- immAlign = evaluateImmediateOffset ( operands [ 3 ] , compiler ) ;
2067
- if ( immAlign < 0 ) {
2068
- compiler . currentType = Type . void ;
2069
- return module . unreachable ( ) ;
2070
- }
2071
- if ( immAlign > naturalAlign ) {
2072
- compiler . error (
2073
- DiagnosticCode . _0_must_be_a_value_between_1_and_2_inclusive ,
2074
- operands [ 3 ] . range , "Alignment" , "0" , naturalAlign . toString ( )
2075
- ) ;
2047
+ var immOffset = 0 ;
2048
+ var immAlign = type . byteSize ;
2049
+ if ( numOperands >= 3 ) {
2050
+ immOffset = evaluateImmediateOffset ( operands [ 2 ] , compiler ) ; // reports
2051
+ if ( immOffset < 0 ) {
2076
2052
compiler . currentType = Type . void ;
2077
2053
return module . unreachable ( ) ;
2078
2054
}
2079
- if ( ! isPowerOf2 ( immAlign ) ) {
2080
- compiler . error (
2081
- DiagnosticCode . _0_must_be_a_power_of_two ,
2082
- operands [ 3 ] . range , "Alignment"
2083
- ) ;
2084
- compiler . currentType = Type . void ;
2085
- return module . unreachable ( ) ;
2055
+ if ( numOperands == 4 ) {
2056
+ immAlign = evaluateImmediateAlign ( operands [ 3 ] , immAlign , compiler ) ; // reports
2057
+ if ( immAlign < 0 ) {
2058
+ compiler . currentType = Type . void ;
2059
+ return module . unreachable ( ) ;
2060
+ }
2086
2061
}
2087
- } else {
2088
- immAlign = naturalAlign ;
2089
2062
}
2090
2063
compiler . currentType = Type . void ;
2091
2064
return module . store ( type . byteSize , arg0 , arg1 , inType . toNativeType ( ) , immOffset , immAlign ) ;
@@ -2555,6 +2528,122 @@ function builtin_memory_fill(ctx: BuiltinContext): ExpressionRef {
2555
2528
}
2556
2529
builtins . set ( BuiltinNames . memory_fill , builtin_memory_fill ) ;
2557
2530
2531
+ // memory.data(size[, align]) -> usize
2532
+ // memory.data<T>(values[, align]) -> usize
2533
+ function builtin_memory_data ( ctx : BuiltinContext ) : ExpressionRef {
2534
+ var compiler = ctx . compiler ;
2535
+ var module = compiler . module ;
2536
+ compiler . currentType = Type . i32 ;
2537
+ if (
2538
+ checkTypeOptional ( ctx ) |
2539
+ checkArgsOptional ( ctx , 1 , 2 )
2540
+ ) return module . unreachable ( ) ;
2541
+ var typeArguments = ctx . typeArguments ;
2542
+ var operands = ctx . operands ;
2543
+ var numOperands = operands . length ;
2544
+ var usizeType = compiler . options . usizeType ;
2545
+ var offset : i64 ;
2546
+ if ( typeArguments !== null && typeArguments . length > 0 ) { // data<T>(values[, align])
2547
+ let elementType = typeArguments [ 0 ] ;
2548
+ if ( ! elementType . is ( TypeFlags . VALUE ) ) {
2549
+ compiler . error (
2550
+ DiagnosticCode . Operation_0_cannot_be_applied_to_type_1 ,
2551
+ ctx . reportNode . typeArgumentsRange , "memory.data" , elementType . toString ( )
2552
+ ) ;
2553
+ compiler . currentType = usizeType ;
2554
+ return module . unreachable ( ) ;
2555
+ }
2556
+ let nativeElementType = elementType . toNativeType ( ) ;
2557
+ let valuesOperand = operands [ 0 ] ;
2558
+ if ( valuesOperand . kind != NodeKind . LITERAL || ( < LiteralExpression > valuesOperand ) . literalKind != LiteralKind . ARRAY ) {
2559
+ compiler . error (
2560
+ DiagnosticCode . Array_literal_expected ,
2561
+ operands [ 0 ] . range
2562
+ ) ;
2563
+ compiler . currentType = usizeType ;
2564
+ return module . unreachable ( ) ;
2565
+ }
2566
+ let expressions = ( < ArrayLiteralExpression > valuesOperand ) . elementExpressions ;
2567
+ let numElements = expressions . length ;
2568
+ let exprs = new Array < ExpressionRef > ( numElements ) ;
2569
+ let isStatic = true ;
2570
+ for ( let i = 0 ; i < numElements ; ++ i ) {
2571
+ let expression = expressions [ i ] ;
2572
+ if ( expression ) {
2573
+ let expr = module . precomputeExpression (
2574
+ compiler . compileExpression ( < Expression > expression , elementType ,
2575
+ Constraints . CONV_IMPLICIT | Constraints . WILL_RETAIN
2576
+ )
2577
+ ) ;
2578
+ if ( getExpressionId ( expr ) == ExpressionId . Const ) {
2579
+ assert ( getExpressionType ( expr ) == nativeElementType ) ;
2580
+ exprs [ i ] = expr ;
2581
+ } else {
2582
+ isStatic = false ;
2583
+ }
2584
+ } else {
2585
+ exprs [ i ] = compiler . makeZero ( elementType ) ;
2586
+ }
2587
+ }
2588
+ if ( ! isStatic ) {
2589
+ compiler . error (
2590
+ DiagnosticCode . Expression_must_be_a_compile_time_constant ,
2591
+ valuesOperand . range
2592
+ ) ;
2593
+ compiler . currentType = usizeType ;
2594
+ return module . unreachable ( ) ;
2595
+ }
2596
+ let align = elementType . byteSize ;
2597
+ if ( numOperands == 2 ) {
2598
+ align = evaluateImmediateAlign ( operands [ 1 ] , align , compiler ) ; // reports
2599
+ if ( align < 0 ) {
2600
+ compiler . currentType = usizeType ;
2601
+ return module . unreachable ( ) ;
2602
+ }
2603
+ }
2604
+ let buf = new Uint8Array ( numElements * elementType . byteSize ) ;
2605
+ assert ( compiler . writeStaticBuffer ( buf , 0 , elementType , exprs ) == buf . byteLength ) ;
2606
+ offset = compiler . addMemorySegment ( buf , align ) . offset ;
2607
+ } else { // data(size[, align])
2608
+ let arg0 = compiler . precomputeExpression ( operands [ 0 ] , Type . i32 , Constraints . CONV_IMPLICIT ) ;
2609
+ if ( getExpressionId ( arg0 ) != ExpressionId . Const ) {
2610
+ compiler . error (
2611
+ DiagnosticCode . Expression_must_be_a_compile_time_constant ,
2612
+ operands [ 0 ] . range
2613
+ ) ;
2614
+ compiler . currentType = usizeType ;
2615
+ return module . unreachable ( ) ;
2616
+ }
2617
+ let size = getConstValueI32 ( arg0 ) ;
2618
+ if ( size < 1 ) {
2619
+ compiler . error (
2620
+ DiagnosticCode . _0_must_be_a_value_between_1_and_2_inclusive ,
2621
+ operands [ 0 ] . range , "1" , i32 . MAX_VALUE . toString ( )
2622
+ ) ;
2623
+ compiler . currentType = usizeType ;
2624
+ return module . unreachable ( ) ;
2625
+ }
2626
+ let align = 16 ;
2627
+ if ( numOperands == 2 ) {
2628
+ align = evaluateImmediateAlign ( operands [ 1 ] , align , compiler ) ; // reports
2629
+ if ( align < 0 ) {
2630
+ compiler . currentType = usizeType ;
2631
+ return module . unreachable ( ) ;
2632
+ }
2633
+ }
2634
+ offset = compiler . addMemorySegment ( new Uint8Array ( size ) , align ) . offset ;
2635
+ }
2636
+ // FIXME: what if recompiles happen? recompiles are bad.
2637
+ compiler . currentType = usizeType ;
2638
+ if ( usizeType == Type . usize32 ) {
2639
+ assert ( ! i64_high ( offset ) ) ;
2640
+ return module . i32 ( i64_low ( offset ) ) ;
2641
+ } else {
2642
+ return module . i64 ( i64_low ( offset ) , i64_high ( offset ) ) ;
2643
+ }
2644
+ }
2645
+ builtins . set ( BuiltinNames . memory_data , builtin_memory_data ) ;
2646
+
2558
2647
// === Helpers ================================================================================
2559
2648
2560
2649
// changetype<T!>(value: *) -> T
@@ -3496,38 +3585,24 @@ function builtin_v128_load_splat(ctx: BuiltinContext): ExpressionRef {
3496
3585
var type = typeArguments [ 0 ] ;
3497
3586
var arg0 = compiler . compileExpression ( operands [ 0 ] , compiler . options . usizeType , Constraints . CONV_IMPLICIT ) ;
3498
3587
var numOperands = operands . length ;
3499
- var immOffset = numOperands >= 2 ? evaluateImmediateOffset ( operands [ 1 ] , compiler ) : 0 ; // reports
3500
- if ( immOffset < 0 ) {
3501
- compiler . currentType = Type . v128 ;
3502
- return module . unreachable ( ) ;
3503
- }
3504
- var immAlign : i32 ;
3505
- var naturalAlign = type . byteSize ;
3506
- if ( numOperands == 3 ) {
3507
- immAlign = evaluateImmediateOffset ( operands [ 2 ] , compiler ) ;
3508
- if ( immAlign < 0 ) {
3588
+ var immOffset = 0 ;
3589
+ var immAlign = type . byteSize ;
3590
+ if ( numOperands >= 2 ) {
3591
+ immOffset = evaluateImmediateOffset ( operands [ 1 ] , compiler ) ; // reports
3592
+ if ( immOffset < 0 ) {
3509
3593
compiler . currentType = Type . v128 ;
3510
3594
return module . unreachable ( ) ;
3511
3595
}
3512
- } else {
3513
- immAlign = naturalAlign ;
3596
+ if ( numOperands == 3 ) {
3597
+ immAlign = evaluateImmediateAlign ( operands [ 2 ] , immAlign , compiler ) ; // reports
3598
+ if ( immAlign < 0 ) {
3599
+ compiler . currentType = Type . v128 ;
3600
+ return module . unreachable ( ) ;
3601
+ }
3602
+ }
3514
3603
}
3515
3604
compiler . currentType = Type . v128 ;
3516
3605
if ( ! type . is ( TypeFlags . REFERENCE ) ) {
3517
- if ( immAlign > naturalAlign ) {
3518
- compiler . error (
3519
- DiagnosticCode . _0_must_be_a_value_between_1_and_2_inclusive ,
3520
- operands [ 2 ] . range , "Alignment" , "0" , naturalAlign . toString ( )
3521
- ) ;
3522
- return module . unreachable ( ) ;
3523
- }
3524
- if ( ! isPowerOf2 ( immAlign ) ) {
3525
- compiler . error (
3526
- DiagnosticCode . _0_must_be_a_power_of_two ,
3527
- operands [ 2 ] . range , "Alignment"
3528
- ) ;
3529
- return module . unreachable ( ) ;
3530
- }
3531
3606
switch ( type . kind ) {
3532
3607
case TypeKind . I8 :
3533
3608
case TypeKind . U8 : {
@@ -3578,38 +3653,24 @@ function builtin_v128_load_ext(ctx: BuiltinContext): ExpressionRef {
3578
3653
var type = typeArguments [ 0 ] ;
3579
3654
var arg0 = compiler . compileExpression ( operands [ 0 ] , compiler . options . usizeType , Constraints . CONV_IMPLICIT ) ;
3580
3655
var numOperands = operands . length ;
3581
- var immOffset = numOperands >= 2 ? evaluateImmediateOffset ( operands [ 1 ] , compiler ) : 0 ; // reports
3582
- if ( immOffset < 0 ) {
3583
- compiler . currentType = Type . v128 ;
3584
- return module . unreachable ( ) ;
3585
- }
3586
- var immAlign : i32 ;
3587
- var naturalAlign = type . byteSize ;
3588
- if ( numOperands == 3 ) {
3589
- immAlign = evaluateImmediateOffset ( operands [ 2 ] , compiler ) ;
3590
- if ( immAlign < 0 ) {
3656
+ var immOffset = 0 ;
3657
+ var immAlign = type . byteSize ;
3658
+ if ( numOperands >= 2 ) {
3659
+ immOffset = evaluateImmediateOffset ( operands [ 1 ] , compiler ) ; // reports
3660
+ if ( immOffset < 0 ) {
3591
3661
compiler . currentType = Type . v128 ;
3592
3662
return module . unreachable ( ) ;
3593
3663
}
3594
- } else {
3595
- immAlign = naturalAlign ;
3664
+ if ( numOperands == 3 ) {
3665
+ immAlign = evaluateImmediateAlign ( operands [ 2 ] , immAlign , compiler ) ; // reports
3666
+ if ( immAlign < 0 ) {
3667
+ compiler . currentType = Type . v128 ;
3668
+ return module . unreachable ( ) ;
3669
+ }
3670
+ }
3596
3671
}
3597
3672
compiler . currentType = Type . v128 ;
3598
3673
if ( ! type . is ( TypeFlags . REFERENCE ) ) {
3599
- if ( immAlign > naturalAlign ) {
3600
- compiler . error (
3601
- DiagnosticCode . _0_must_be_a_value_between_1_and_2_inclusive ,
3602
- operands [ 2 ] . range , "Alignment" , "0" , naturalAlign . toString ( )
3603
- ) ;
3604
- return module . unreachable ( ) ;
3605
- }
3606
- if ( ! isPowerOf2 ( immAlign ) ) {
3607
- compiler . error (
3608
- DiagnosticCode . _0_must_be_a_power_of_two ,
3609
- operands [ 2 ] . range , "Alignment"
3610
- ) ;
3611
- return module . unreachable ( ) ;
3612
- }
3613
3674
switch ( type . kind ) {
3614
3675
case TypeKind . I8 : return module . simd_load ( SIMDLoadOp . LoadI8ToI16x8 , arg0 , immOffset , immAlign ) ;
3615
3676
case TypeKind . U8 : return module . simd_load ( SIMDLoadOp . LoadU8ToU16x8 , arg0 , immOffset , immAlign ) ;
@@ -8196,6 +8257,27 @@ function evaluateImmediateOffset(expression: Expression, compiler: Compiler): i3
8196
8257
return value ;
8197
8258
}
8198
8259
8260
+ /** Evaluates a compile-time constant immediate align argument. */
8261
+ function evaluateImmediateAlign ( expression : Expression , naturalAlign : i32 , compiler : Compiler ) : i32 {
8262
+ var align = evaluateImmediateOffset ( expression , compiler ) ;
8263
+ if ( align < 0 ) return align ;
8264
+ if ( align < 1 || naturalAlign > 16 ) {
8265
+ compiler . error (
8266
+ DiagnosticCode . _0_must_be_a_value_between_1_and_2_inclusive ,
8267
+ expression . range , "Alignment" , "1" , naturalAlign . toString ( )
8268
+ ) ;
8269
+ return - 1 ;
8270
+ }
8271
+ if ( ! isPowerOf2 ( align ) ) {
8272
+ compiler . error (
8273
+ DiagnosticCode . _0_must_be_a_power_of_two ,
8274
+ expression . range , "Alignment"
8275
+ ) ;
8276
+ return - 1 ;
8277
+ }
8278
+ return align ;
8279
+ }
8280
+
8199
8281
/** Checks that the specified feature is enabled. */
8200
8282
function checkFeatureEnabled ( ctx : BuiltinContext , feature : Feature ) : i32 {
8201
8283
var compiler = ctx . compiler ;
0 commit comments