From b453ba63f321b3aff82fadf647d705b7f2b9c252 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 8 Feb 2017 16:46:05 -0500 Subject: [PATCH 1/8] lower x^literal as x^Val{literal} for small integer literals (closes #20527) --- base/intfuncs.jl | 5 +++++ src/ast.c | 14 ++++++++++++++ src/julia-syntax.scm | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 3331011ce5a2b..6df629dcf57ea 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -195,6 +195,11 @@ end ^(x::Number, p::Integer) = power_by_squaring(x,p) ^(x, p::Integer) = power_by_squaring(x,p) +# x^p for small literal p is lowered to x^Val{p}, +# to enable compile-time optimizations specialized to p. +# However, we still need a fallback that calls the general ^: +^{p}(x, ::Type{Val{p}}) = x^p + # b^p mod m """ diff --git a/src/ast.c b/src/ast.c index f895029980991..211d7265d4bf0 100644 --- a/src/ast.c +++ b/src/ast.c @@ -245,12 +245,26 @@ value_t fl_julia_scalar(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) return fl_ctx->F; } +value_t fl_julia_smallnum(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) +{ + argcount(fl_ctx, "julia-smallnum?", nargs, 1); + if (isfixnum(args[0]) && numval(args[0]) < 32 && numval(args[0]) > -32) + return fl_ctx->T; + else if (iscvalue(args[0]) && fl_ctx->jl_sym == cv_type((cvalue_t*)ptr(args[0]))) { + jl_value_t *v = *(jl_value_t**)cptr(args[0]); + if (jl_is_long(v) && jl_unbox_long(v) < 32 && jl_unbox_long(v) > -32) + return fl_ctx->T; + } + return fl_ctx->F; +} + static const builtinspec_t julia_flisp_ast_ext[] = { { "defined-julia-global", fl_defined_julia_global }, { "invoke-julia-macro", fl_invoke_julia_macro }, { "current-julia-module", fl_current_julia_module }, { "current-julia-module-counter", fl_current_module_counter }, { "julia-scalar?", fl_julia_scalar }, + { "julia-smallnum?", fl_julia_smallnum }, { NULL, NULL } }; diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 56723fbc2f533..67f25804e0f33 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -2057,6 +2057,10 @@ (expand-forms `(call (core _apply) ,f ,@(tuple-wrap argl '()))))) + ((and (eq? f '^) (length= e 4) (julia-smallnum? (cadddr e))) + (expand-forms + `(call ^ ,(caddr e) (call (core apply_type) (top Val) ,(cadddr e))))) + ((and (eq? f '*) (length= e 4)) (expand-transposed-op e From ce13a793f53dd61c14c38173adb0dc2764473879 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 8 Feb 2017 17:55:59 -0500 Subject: [PATCH 2/8] simplify smallnum check since all Ints get inlined as fixnums into Scheme, regardless of their origin --- src/ast.c | 14 -------------- src/julia-syntax.scm | 4 +++- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/ast.c b/src/ast.c index 211d7265d4bf0..f895029980991 100644 --- a/src/ast.c +++ b/src/ast.c @@ -245,26 +245,12 @@ value_t fl_julia_scalar(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) return fl_ctx->F; } -value_t fl_julia_smallnum(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) -{ - argcount(fl_ctx, "julia-smallnum?", nargs, 1); - if (isfixnum(args[0]) && numval(args[0]) < 32 && numval(args[0]) > -32) - return fl_ctx->T; - else if (iscvalue(args[0]) && fl_ctx->jl_sym == cv_type((cvalue_t*)ptr(args[0]))) { - jl_value_t *v = *(jl_value_t**)cptr(args[0]); - if (jl_is_long(v) && jl_unbox_long(v) < 32 && jl_unbox_long(v) > -32) - return fl_ctx->T; - } - return fl_ctx->F; -} - static const builtinspec_t julia_flisp_ast_ext[] = { { "defined-julia-global", fl_defined_julia_global }, { "invoke-julia-macro", fl_invoke_julia_macro }, { "current-julia-module", fl_current_julia_module }, { "current-julia-module-counter", fl_current_module_counter }, { "julia-scalar?", fl_julia_scalar }, - { "julia-smallnum?", fl_julia_smallnum }, { NULL, NULL } }; diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 67f25804e0f33..3efe0950b0918 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1771,6 +1771,8 @@ (extract (cdr params) (cons p newparams) whereparams))))) (extract (cddr e) '() '())) +(define (smallnum? x) (and (integer? x) (< x 32) (> x -32))) + ;; table mapping expression head to a function expanding that form (define expand-table (table @@ -2057,7 +2059,7 @@ (expand-forms `(call (core _apply) ,f ,@(tuple-wrap argl '()))))) - ((and (eq? f '^) (length= e 4) (julia-smallnum? (cadddr e))) + ((and (eq? f '^) (length= e 4) (smallnum? (cadddr e))) (expand-forms `(call ^ ,(caddr e) (call (core apply_type) (top Val) ,(cadddr e))))) From 7eeefee71b708d908d3cf98a23df4dfb6f7f8705 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 8 Feb 2017 18:06:09 -0500 Subject: [PATCH 3/8] do x^Val{p} transformation for all literal p, not just small ones --- src/julia-syntax.scm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 3efe0950b0918..2734420a0ce6d 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1771,8 +1771,6 @@ (extract (cdr params) (cons p newparams) whereparams))))) (extract (cddr e) '() '())) -(define (smallnum? x) (and (integer? x) (< x 32) (> x -32))) - ;; table mapping expression head to a function expanding that form (define expand-table (table @@ -2059,7 +2057,7 @@ (expand-forms `(call (core _apply) ,f ,@(tuple-wrap argl '()))))) - ((and (eq? f '^) (length= e 4) (smallnum? (cadddr e))) + ((and (eq? f '^) (length= e 4) (integer? (cadddr e))) (expand-forms `(call ^ ,(caddr e) (call (core apply_type) (top Val) ,(cadddr e))))) From 5411736cc5626cc17c02ffa57cc0af68a09898c7 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 8 Feb 2017 18:07:40 -0500 Subject: [PATCH 4/8] fix comment --- base/intfuncs.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 6df629dcf57ea..a7eb603ad61f3 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -195,7 +195,7 @@ end ^(x::Number, p::Integer) = power_by_squaring(x,p) ^(x, p::Integer) = power_by_squaring(x,p) -# x^p for small literal p is lowered to x^Val{p}, +# x^p for any literal integer p is lowered to x^Val{p}, # to enable compile-time optimizations specialized to p. # However, we still need a fallback that calls the general ^: ^{p}(x, ::Type{Val{p}}) = x^p From a7f1f45d5020388d9bddee3f5a410fc1c8daecef Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 8 Feb 2017 21:47:30 -0500 Subject: [PATCH 5/8] docs for x^Val{p} --- NEWS.md | 4 ++++ base/promotion.jl | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/NEWS.md b/NEWS.md index 5f0e9d6781dab..c12e142972bc5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -22,6 +22,10 @@ New language features Language changes ---------------- + * `x^n` for integer literals `n` (e.g. `x^3` or `x^-3`) is now + lowered to `x^Val{n}`, to enable compile-time specialization + for literal integer exponents ([#20530]). + * "Inner constructor" syntax for parametric types is deprecated. For example, in this definition: ``` diff --git a/base/promotion.jl b/base/promotion.jl index 253db5b78bc8c..7faef91b7683c 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -253,6 +253,11 @@ end Exponentiation operator. If `x` is a matrix, computes matrix exponentiation. +If `y` is an `Int` literal (e.g. `x^2` or `x^-3`), the Julia code +`x^y` is transformed to `x^Val{y}`, to enable compile-time +specialization on the value of the exponent. (As a default fallback, +however, `x^Val{y}` simply calls the `^(x,y)` function.) + ```jldoctest julia> 3^5 243 From f23f25098f881744b491e37046b89943dbaebd17 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 9 Feb 2017 08:32:35 -0500 Subject: [PATCH 6/8] documentation tweak --- base/promotion.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/promotion.jl b/base/promotion.jl index 7faef91b7683c..98efd35b044a3 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -253,8 +253,8 @@ end Exponentiation operator. If `x` is a matrix, computes matrix exponentiation. -If `y` is an `Int` literal (e.g. `x^2` or `x^-3`), the Julia code -`x^y` is transformed to `x^Val{y}`, to enable compile-time +If `y` is an `Int` literal (e.g. `2` in `x^2` or `-3` in `x^-3`), the Julia code +`x^y` is transformed by the compiler to `x^Val{y}`, to enable compile-time specialization on the value of the exponent. (As a default fallback, however, `x^Val{y}` simply calls the `^(x,y)` function.) From 3a0d354b6c6a29e4c8b4819cf5cb5409f4cb9198 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 9 Feb 2017 08:38:46 -0500 Subject: [PATCH 7/8] added test for x^literal --- test/numbers.jl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/numbers.jl b/test/numbers.jl index 50ae87241a521..d46fb92f94380 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -2902,6 +2902,18 @@ end @test rem2pi(T(-4), RoundUp) == -4 end +import Base.^ +immutable PR20530; end +^(::PR20530, p::Int) = 1 +^{p}(::PR20530, ::Type{Val{p}}) = 2 +@testset "literal powers" begin + x = PR20530() + p = 2 + @test x^p == 1 + @test x^2 == 2 + @test [x,x,x].^2 == [2,2,2] +end + @testset "iszero" begin # Numeric scalars for T in [Float16, Float32, Float64, BigFloat, From d1dab59f3baceaa3bc77a7f646c436291b749ce4 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 16 Feb 2017 16:09:25 -0500 Subject: [PATCH 8/8] note experimental feature [ci skip] --- NEWS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index c12e142972bc5..5a40283cb17ce 100644 --- a/NEWS.md +++ b/NEWS.md @@ -22,10 +22,6 @@ New language features Language changes ---------------- - * `x^n` for integer literals `n` (e.g. `x^3` or `x^-3`) is now - lowered to `x^Val{n}`, to enable compile-time specialization - for literal integer exponents ([#20530]). - * "Inner constructor" syntax for parametric types is deprecated. For example, in this definition: ``` @@ -77,6 +73,10 @@ Language changes * The `typealias` keyword is deprecated, and should be replaced with `Vector{T} = Array{T,1}` or a `const` assignment. + * Experimental feature: `x^n` for integer literals `n` (e.g. `x^3` + or `x^-3`) is now lowered to `x^Val{n}`, to enable compile-time + specialization for literal integer exponents ([#20530]). + Breaking changes ----------------