@@ -3855,6 +3855,8 @@ export class Compiler extends DiagnosticEmitter {
3855
3855
private f64ModInstance : Function | null = null ;
3856
3856
private f32PowInstance : Function | null = null ;
3857
3857
private f64PowInstance : Function | null = null ;
3858
+ private i32PowInstance : Function | null = null ;
3859
+ private i64PowInstance : Function | null = null ;
3858
3860
3859
3861
private compileBinaryExpression (
3860
3862
expression : BinaryExpression ,
@@ -4786,82 +4788,198 @@ export class Compiler extends DiagnosticEmitter {
4786
4788
) ;
4787
4789
return this . module . unreachable ( ) ;
4788
4790
}
4791
+ if ( compound ) {
4792
+ leftExpr = this . ensureSmallIntegerWrap ( leftExpr , leftType ) ;
4793
+ rightExpr = this . compileExpression ( right , leftType , Constraints . CONV_IMPLICIT ) ;
4794
+ rightType = commonType = this . currentType ;
4795
+ } else {
4796
+ rightExpr = this . compileExpression ( right , leftType ) ;
4797
+ rightType = this . currentType ;
4798
+ commonType = Type . commonDenominator ( leftType , rightType , false ) ;
4799
+ if ( commonType ) {
4800
+ leftExpr = this . convertExpression ( leftExpr ,
4801
+ leftType , commonType ,
4802
+ false , true , // !
4803
+ left
4804
+ ) ;
4805
+ leftType = commonType ;
4806
+ rightExpr = this . convertExpression ( rightExpr ,
4807
+ rightType , commonType ,
4808
+ false , true , // !
4809
+ right
4810
+ ) ;
4811
+ rightType = commonType ;
4812
+ } else {
4813
+ this . error (
4814
+ DiagnosticCode . Operator_0_cannot_be_applied_to_types_1_and_2 ,
4815
+ expression . range , "**" , leftType . toString ( ) , rightType . toString ( )
4816
+ ) ;
4817
+ this . currentType = contextualType ;
4818
+ return module . unreachable ( ) ;
4819
+ }
4820
+ }
4789
4821
4790
- let targetType = leftType ;
4791
4822
let instance : Function | null ;
4792
-
4793
- // Mathf.pow if lhs is f32 (result is f32)
4794
- if ( this . currentType . kind == TypeKind . F32 ) {
4795
- rightExpr = this . compileExpression ( right , Type . f32 , Constraints . CONV_IMPLICIT ) ;
4796
- rightType = this . currentType ;
4797
- instance = this . f32PowInstance ;
4798
- if ( ! instance ) {
4799
- let namespace = this . program . lookupGlobal ( CommonNames . Mathf ) ;
4800
- if ( ! namespace ) {
4801
- this . error (
4802
- DiagnosticCode . Cannot_find_name_0 ,
4803
- expression . range , "Mathf"
4804
- ) ;
4823
+ switch ( commonType . kind ) {
4824
+ case TypeKind . BOOL : {
4825
+ expr = module . select (
4826
+ module . i32 ( 1 ) ,
4827
+ module . binary ( BinaryOp . EqI32 , rightExpr , module . i32 ( 0 ) ) ,
4828
+ leftExpr
4829
+ ) ;
4830
+ break ;
4831
+ }
4832
+ case TypeKind . I8 :
4833
+ case TypeKind . U8 :
4834
+ case TypeKind . I16 :
4835
+ case TypeKind . U16 :
4836
+ case TypeKind . I32 :
4837
+ case TypeKind . U32 : {
4838
+ instance = this . i32PowInstance ;
4839
+ if ( ! instance ) {
4840
+ let prototype = this . program . lookupGlobal ( CommonNames . ipow32 ) ;
4841
+ if ( ! prototype ) {
4842
+ this . error (
4843
+ DiagnosticCode . Cannot_find_name_0 ,
4844
+ expression . range , "ipow32"
4845
+ ) ;
4846
+ expr = module . unreachable ( ) ;
4847
+ break ;
4848
+ }
4849
+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4850
+ this . i32PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4851
+ }
4852
+ if ( ! instance || ! this . compileFunction ( instance ) ) {
4805
4853
expr = module . unreachable ( ) ;
4806
- break ;
4854
+ } else {
4855
+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4856
+ if ( commonType . size != 32 ) {
4857
+ expr = this . ensureSmallIntegerWrap ( expr , commonType ) ;
4858
+ }
4807
4859
}
4808
- let namespaceMembers = namespace . members ;
4809
- if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4810
- this . error (
4811
- DiagnosticCode . Cannot_find_name_0 ,
4812
- expression . range , "Mathf.pow"
4813
- ) ;
4860
+ break ;
4861
+ }
4862
+ case TypeKind . I64 :
4863
+ case TypeKind . U64 : {
4864
+ instance = this . i64PowInstance ;
4865
+ if ( ! instance ) {
4866
+ let prototype = this . program . lookupGlobal ( CommonNames . ipow64 ) ;
4867
+ if ( ! prototype ) {
4868
+ this . error (
4869
+ DiagnosticCode . Cannot_find_name_0 ,
4870
+ expression . range , "ipow64"
4871
+ ) ;
4872
+ expr = module . unreachable ( ) ;
4873
+ break ;
4874
+ }
4875
+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4876
+ this . i64PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4877
+ }
4878
+ if ( ! instance || ! this . compileFunction ( instance ) ) {
4814
4879
expr = module . unreachable ( ) ;
4815
- break ;
4880
+ } else {
4881
+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4816
4882
}
4817
- let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4818
- assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4819
- this . f32PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4883
+ break ;
4820
4884
}
4821
-
4822
- // Math.pow otherwise (result is f64)
4823
- // TODO: should the result be converted back?
4824
- } else {
4825
- leftExpr = this . convertExpression ( leftExpr ,
4826
- this . currentType , Type . f64 ,
4827
- false , false ,
4828
- left
4829
- ) ;
4830
- leftType = this . currentType ;
4831
- rightExpr = this . compileExpression ( right , Type . f64 , Constraints . CONV_IMPLICIT ) ;
4832
- rightType = this . currentType ;
4833
- instance = this . f64PowInstance ;
4834
- if ( ! instance ) {
4835
- let namespace = this . program . lookupGlobal ( CommonNames . Math ) ;
4836
- if ( ! namespace ) {
4837
- this . error (
4838
- DiagnosticCode . Cannot_find_name_0 ,
4839
- expression . range , "Math"
4840
- ) ;
4885
+ case TypeKind . ISIZE :
4886
+ case TypeKind . USIZE : {
4887
+ let isWasm64 = this . options . isWasm64 ;
4888
+ instance = isWasm64 ? this . i64PowInstance : this . i32PowInstance ;
4889
+ if ( ! instance ) {
4890
+ let prototype = this . program . lookupGlobal ( isWasm64 ? CommonNames . ipow64 : CommonNames . ipow32 ) ;
4891
+ if ( ! prototype ) {
4892
+ this . error (
4893
+ DiagnosticCode . Cannot_find_name_0 ,
4894
+ expression . range , isWasm64 ? "ipow64" : "ipow32"
4895
+ ) ;
4896
+ expr = module . unreachable ( ) ;
4897
+ break ;
4898
+ }
4899
+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4900
+ instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4901
+ if ( isWasm64 ) {
4902
+ this . i64PowInstance = instance ;
4903
+ } else {
4904
+ this . i32PowInstance = instance ;
4905
+ }
4906
+ }
4907
+ if ( ! instance || ! this . compileFunction ( instance ) ) {
4841
4908
expr = module . unreachable ( ) ;
4842
- break ;
4909
+ } else {
4910
+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4843
4911
}
4844
- let namespaceMembers = namespace . members ;
4845
- if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4846
- this . error (
4847
- DiagnosticCode . Cannot_find_name_0 ,
4848
- expression . range , "Math.pow"
4849
- ) ;
4912
+ break ;
4913
+ }
4914
+ case TypeKind . F32 : {
4915
+ instance = this . f32PowInstance ;
4916
+ if ( ! instance ) {
4917
+ let namespace = this . program . lookupGlobal ( CommonNames . Mathf ) ;
4918
+ if ( ! namespace ) {
4919
+ this . error (
4920
+ DiagnosticCode . Cannot_find_name_0 ,
4921
+ expression . range , "Mathf"
4922
+ ) ;
4923
+ expr = module . unreachable ( ) ;
4924
+ break ;
4925
+ }
4926
+ let namespaceMembers = namespace . members ;
4927
+ if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4928
+ this . error (
4929
+ DiagnosticCode . Cannot_find_name_0 ,
4930
+ expression . range , "Mathf.pow"
4931
+ ) ;
4932
+ expr = module . unreachable ( ) ;
4933
+ break ;
4934
+ }
4935
+ let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4936
+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4937
+ this . f32PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4938
+ }
4939
+ if ( ! instance || ! this . compileFunction ( instance ) ) {
4850
4940
expr = module . unreachable ( ) ;
4851
- break ;
4941
+ } else {
4942
+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4852
4943
}
4853
- let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4854
- assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4855
- this . f64PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4944
+ break ;
4856
4945
}
4857
- }
4858
- if ( ! instance || ! this . compileFunction ( instance ) ) {
4859
- expr = module . unreachable ( ) ;
4860
- } else {
4861
- expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4862
- if ( compound && targetType != this . currentType ) {
4863
- // this yields a proper error if target is i32 for example
4864
- expr = this . convertExpression ( expr , this . currentType , targetType , false , false , expression ) ;
4946
+ // Math.pow otherwise (result is f64)
4947
+ case TypeKind . F64 : {
4948
+ instance = this . f64PowInstance ;
4949
+ if ( ! instance ) {
4950
+ let namespace = this . program . lookupGlobal ( CommonNames . Math ) ;
4951
+ if ( ! namespace ) {
4952
+ this . error (
4953
+ DiagnosticCode . Cannot_find_name_0 ,
4954
+ expression . range , "Math"
4955
+ ) ;
4956
+ expr = module . unreachable ( ) ;
4957
+ break ;
4958
+ }
4959
+ let namespaceMembers = namespace . members ;
4960
+ if ( ! namespaceMembers || ! namespaceMembers . has ( CommonNames . pow ) ) {
4961
+ this . error (
4962
+ DiagnosticCode . Cannot_find_name_0 ,
4963
+ expression . range , "Math.pow"
4964
+ ) ;
4965
+ expr = module . unreachable ( ) ;
4966
+ break ;
4967
+ }
4968
+ let prototype = assert ( namespaceMembers . get ( CommonNames . pow ) ) ;
4969
+ assert ( prototype . kind == ElementKind . FUNCTION_PROTOTYPE ) ;
4970
+ this . f64PowInstance = instance = this . resolver . resolveFunction ( < FunctionPrototype > prototype , null ) ;
4971
+ }
4972
+ if ( ! instance || ! this . compileFunction ( instance ) ) {
4973
+ expr = module . unreachable ( ) ;
4974
+ } else {
4975
+ expr = this . makeCallDirect ( instance , [ leftExpr , rightExpr ] , expression ) ;
4976
+ }
4977
+ break ;
4978
+ }
4979
+ default : {
4980
+ assert ( false ) ;
4981
+ expr = module . unreachable ( ) ;
4982
+ break ;
4865
4983
}
4866
4984
}
4867
4985
break ;
0 commit comments