@@ -38,7 +38,10 @@ import {
3838 Expression ,
3939 LiteralKind ,
4040 StringLiteralExpression ,
41- CallExpression
41+ CallExpression ,
42+ NodeKind ,
43+ LiteralExpression ,
44+ ArrayLiteralExpression
4245} from "./ast" ;
4346
4447import {
@@ -581,6 +584,7 @@ export namespace BuiltinNames {
581584 export const memory_grow = "~lib/memory/memory.grow" ;
582585 export const memory_copy = "~lib/memory/memory.copy" ;
583586 export const memory_fill = "~lib/memory/memory.fill" ;
587+ export const memory_data = "~lib/memory/memory.data" ;
584588
585589 // std/typedarray.ts
586590 export const Int8Array = "~lib/typedarray/Int8Array" ;
@@ -1970,37 +1974,21 @@ function builtin_load(ctx: BuiltinContext): ExpressionRef {
19701974 ) ? contextualType : type ;
19711975 var arg0 = compiler . compileExpression ( operands [ 0 ] , compiler . options . usizeType , Constraints . CONV_IMPLICIT ) ;
19721976 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 ) {
19831982 compiler . currentType = outType ;
19841983 return module . unreachable ( ) ;
19851984 }
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+ }
20011991 }
2002- } else {
2003- immAlign = naturalAlign ;
20041992 }
20051993 compiler . currentType = outType ;
20061994 return module . load (
@@ -2024,6 +2012,7 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
20242012 checkArgsOptional ( ctx , 2 , 4 )
20252013 ) return module . unreachable ( ) ;
20262014 var operands = ctx . operands ;
2015+ var numOperands = operands . length ;
20272016 var typeArguments = ctx . typeArguments ;
20282017 var contextualType = ctx . contextualType ;
20292018 var type = typeArguments ! [ 0 ] ;
@@ -2055,37 +2044,21 @@ function builtin_store(ctx: BuiltinContext): ExpressionRef {
20552044 ) ;
20562045 inType = type ;
20572046 }
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 ) {
20762052 compiler . currentType = Type . void ;
20772053 return module . unreachable ( ) ;
20782054 }
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+ }
20862061 }
2087- } else {
2088- immAlign = naturalAlign ;
20892062 }
20902063 compiler . currentType = Type . void ;
20912064 return module . store ( type . byteSize , arg0 , arg1 , inType . toNativeType ( ) , immOffset , immAlign ) ;
@@ -2555,6 +2528,122 @@ function builtin_memory_fill(ctx: BuiltinContext): ExpressionRef {
25552528}
25562529builtins . set ( BuiltinNames . memory_fill , builtin_memory_fill ) ;
25572530
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+
25582647// === Helpers ================================================================================
25592648
25602649// changetype<T!>(value: *) -> T
@@ -3496,38 +3585,24 @@ function builtin_v128_load_splat(ctx: BuiltinContext): ExpressionRef {
34963585 var type = typeArguments [ 0 ] ;
34973586 var arg0 = compiler . compileExpression ( operands [ 0 ] , compiler . options . usizeType , Constraints . CONV_IMPLICIT ) ;
34983587 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 ) {
35093593 compiler . currentType = Type . v128 ;
35103594 return module . unreachable ( ) ;
35113595 }
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+ }
35143603 }
35153604 compiler . currentType = Type . v128 ;
35163605 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- }
35313606 switch ( type . kind ) {
35323607 case TypeKind . I8 :
35333608 case TypeKind . U8 : {
@@ -3578,38 +3653,24 @@ function builtin_v128_load_ext(ctx: BuiltinContext): ExpressionRef {
35783653 var type = typeArguments [ 0 ] ;
35793654 var arg0 = compiler . compileExpression ( operands [ 0 ] , compiler . options . usizeType , Constraints . CONV_IMPLICIT ) ;
35803655 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 ) {
35913661 compiler . currentType = Type . v128 ;
35923662 return module . unreachable ( ) ;
35933663 }
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+ }
35963671 }
35973672 compiler . currentType = Type . v128 ;
35983673 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- }
36133674 switch ( type . kind ) {
36143675 case TypeKind . I8 : return module . simd_load ( SIMDLoadOp . LoadI8ToI16x8 , arg0 , immOffset , immAlign ) ;
36153676 case TypeKind . U8 : return module . simd_load ( SIMDLoadOp . LoadU8ToU16x8 , arg0 , immOffset , immAlign ) ;
@@ -8196,6 +8257,27 @@ function evaluateImmediateOffset(expression: Expression, compiler: Compiler): i3
81968257 return value ;
81978258}
81988259
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+
81998281/** Checks that the specified feature is enabled. */
82008282function checkFeatureEnabled ( ctx : BuiltinContext , feature : Feature ) : i32 {
82018283 var compiler = ctx . compiler ;
0 commit comments