@@ -172,13 +172,38 @@ unwrap_transpose_arg <- function(arg, scope, ..., hoist) {
172172}
173173
174174# Whether it's safe and useful to write into dest (no aliasing with inputs)
175- can_use_output <- function (dest , left , right ) {
175+ assert_dest_dims_compatible <- function (dest , expected_dims , context ) {
176+ if (is.null(dest ) || is.null(expected_dims )) {
177+ return (invisible (TRUE ))
178+ }
179+ expected_rank <- length(expected_dims )
180+ if (dest @ rank != expected_rank ) {
181+ stop(" assignment target has incompatible rank for " , context , call. = FALSE )
182+ }
183+ for (i in seq_len(expected_rank )) {
184+ dest_dim <- dest @ dims [[i ]]
185+ expected_dim <- expected_dims [[i ]]
186+ if (is_wholenumber(dest_dim ) && is_wholenumber(expected_dim )) {
187+ if (! identical(as.integer(dest_dim ), as.integer(expected_dim ))) {
188+ stop(
189+ " assignment target has incompatible dimensions for " ,
190+ context ,
191+ call. = FALSE
192+ )
193+ }
194+ }
195+ }
196+ invisible (TRUE )
197+ }
198+
199+ can_use_output <- function (dest , left , right , expected_dims = NULL , context ) {
176200 if (is.null(dest )) {
177201 return (FALSE )
178202 }
179203 if (! identical(dest @ mode , " double" )) {
180204 return (FALSE )
181205 }
206+ assert_dest_dims_compatible(dest , expected_dims , context )
182207 output_name <- dest @ name
183208 # check output name is not the same as left or right
184209 ! identical(output_name , as.character(left )) &&
@@ -230,15 +255,24 @@ gemm <- function(
230255 ldc_expr ,
231256 scope ,
232257 hoist ,
233- dest = NULL
258+ dest = NULL ,
259+ context = " gemm"
234260) {
235261 if (! inherits(hoist , " environment" )) {
236262 stop(" internal: hoist must be a hoist environment" )
237263 }
238264 A_name <- ensure_blas_operand_name(left , hoist )
239265 B_name <- ensure_blas_operand_name(right , hoist )
240266
241- if (can_use_output(dest , left , right )) {
267+ if (
268+ can_use_output(
269+ dest ,
270+ left ,
271+ right ,
272+ expected_dims = list (m , n ),
273+ context = context
274+ )
275+ ) {
242276 hoist $ emit(glue(
243277 " call dgemm('{opA}','{opB}', {blas_int(m)}, {blas_int(n)}, {blas_int(k)}, 1.0_c_double, {A_name}, {blas_int(lda)}, {B_name}, {blas_int(ldb)}, 0.0_c_double, {dest@name}, {blas_int(ldc_expr)})"
244278 ))
@@ -268,15 +302,24 @@ gemv <- function(
268302 out_dims ,
269303 scope ,
270304 hoist ,
271- dest = NULL
305+ dest = NULL ,
306+ context = " gemv"
272307) {
273308 if (! inherits(hoist , " environment" )) {
274309 stop(" internal: hoist must be a hoist environment" )
275310 }
276311 A_name <- ensure_blas_operand_name(A , hoist )
277312 x_name <- ensure_blas_operand_name(x , hoist )
278313
279- if (can_use_output(dest , A , x )) {
314+ if (
315+ can_use_output(
316+ dest ,
317+ A ,
318+ x ,
319+ expected_dims = out_dims ,
320+ context = context
321+ )
322+ ) {
280323 # Assign output to output destination
281324 hoist $ emit(glue(
282325 " call dgemv('{transA}', {blas_int(m)}, {blas_int(n)}, 1.0_c_double, {A_name}, {blas_int(lda)}, {x_name}, 1, 0.0_c_double, {dest@name}, 1)"
@@ -302,7 +345,8 @@ syrk <- function(
302345 X ,
303346 scope ,
304347 hoist ,
305- dest = NULL
348+ dest = NULL ,
349+ context = " syrk"
306350) {
307351 if (! inherits(hoist , " environment" )) {
308352 stop(" internal: hoist must be a hoist environment" )
@@ -323,7 +367,15 @@ syrk <- function(
323367 lda <- x_dims $ rows
324368
325369 # Output is symmetric n x n matrix
326- if (can_use_output(dest , X , X )) {
370+ if (
371+ can_use_output(
372+ dest ,
373+ X ,
374+ X ,
375+ expected_dims = list (n , n ),
376+ context = context
377+ )
378+ ) {
327379 hoist $ emit(glue(
328380 " call dsyrk('U', '{trans}', {blas_int(n)}, {blas_int(k)}, 1.0_c_double, {X_name}, {blas_int(lda)}, 0.0_c_double, {dest@name}, {blas_int(n)})"
329381 ))
@@ -361,7 +413,14 @@ end do"
361413 Fortran(output_var @ name , output_var )
362414}
363415
364- outer_mul <- function (x , y , scope , hoist , dest = NULL ) {
416+ outer_mul <- function (
417+ x ,
418+ y ,
419+ scope ,
420+ hoist ,
421+ dest = NULL ,
422+ context = " outer"
423+ ) {
365424 if (! inherits(hoist , " environment" )) {
366425 stop(" internal: hoist must be a hoist environment" )
367426 }
@@ -379,7 +438,15 @@ outer_mul <- function(x, y, scope, hoist, dest = NULL) {
379438 x_name <- ensure_blas_operand_name(x , hoist )
380439 y_name <- ensure_blas_operand_name(y , hoist )
381440
382- if (can_use_output(dest , x , y )) {
441+ if (
442+ can_use_output(
443+ dest ,
444+ x ,
445+ y ,
446+ expected_dims = list (m , n ),
447+ context = context
448+ )
449+ ) {
383450 hoist $ emit(glue(" {dest@name} = 0.0_c_double" ))
384451 hoist $ emit(glue(
385452 " call dger({blas_int(m)}, {blas_int(n)}, 1.0_c_double, {x_name}, 1, {y_name}, 1, {dest@name}, {blas_int(m)})"
@@ -405,7 +472,8 @@ triangular_solve <- function(
405472 diag ,
406473 scope ,
407474 hoist ,
408- dest = NULL
475+ dest = NULL ,
476+ context = " triangular solve"
409477) {
410478 if (! inherits(hoist , " environment" )) {
411479 stop(" internal: hoist must be a hoist environment" )
@@ -438,7 +506,15 @@ triangular_solve <- function(
438506
439507 A_name <- ensure_blas_operand_name(A , hoist )
440508
441- if (can_use_output(dest , A , B )) {
509+ if (
510+ can_use_output(
511+ dest ,
512+ A ,
513+ B ,
514+ expected_dims = B @ value @ dims ,
515+ context = context
516+ )
517+ ) {
442518 hoist $ emit(glue(" {dest@name} = {B}" ))
443519 B_name <- dest @ name
444520 out_var <- dest
@@ -492,7 +568,8 @@ crossprod_like <- function(
492568 X = x ,
493569 scope = scope ,
494570 hoist = hoist ,
495- dest = dest
571+ dest = dest ,
572+ context = context
496573 ))
497574 }
498575
@@ -526,7 +603,8 @@ crossprod_like <- function(
526603 ldc_expr = ldc_expr ,
527604 scope = scope ,
528605 hoist = hoist ,
529- dest = dest
606+ dest = dest ,
607+ context = context
530608 )
531609}
532610
@@ -595,7 +673,8 @@ r2f_handlers[["%*%"]] <- function(args, scope, ..., hoist = NULL, dest = NULL) {
595673 out_dims = list (out_len , 1L ),
596674 scope = scope ,
597675 hoist = hoist ,
598- dest = dest
676+ dest = dest ,
677+ context = " %*%"
599678 ))
600679 }
601680 # Vector-Matrix: use GEMV with transpose
@@ -614,7 +693,8 @@ r2f_handlers[["%*%"]] <- function(args, scope, ..., hoist = NULL, dest = NULL) {
614693 out_dims = list (1L , out_len ),
615694 scope = scope ,
616695 hoist = hoist ,
617- dest = dest
696+ dest = dest ,
697+ context = " %*%"
618698 ))
619699 }
620700
@@ -634,7 +714,8 @@ r2f_handlers[["%*%"]] <- function(args, scope, ..., hoist = NULL, dest = NULL) {
634714 ldc_expr = ldc_expr ,
635715 scope = scope ,
636716 hoist = hoist ,
637- dest = dest
717+ dest = dest ,
718+ context = " %*%"
638719 )
639720}
640721
@@ -725,7 +806,14 @@ r2f_handlers[["outer"]] <- function(
725806 }
726807 x <- r2f(x_arg , scope , ... , hoist = hoist )
727808 y <- r2f(y_arg , scope , ... , hoist = hoist )
728- outer_mul(x , y , scope = scope , hoist = hoist , dest = dest )
809+ outer_mul(
810+ x ,
811+ y ,
812+ scope = scope ,
813+ hoist = hoist ,
814+ dest = dest ,
815+ context = " outer"
816+ )
729817}
730818
731819r2f_handlers [[" %o%" ]] <- function (
@@ -738,7 +826,14 @@ r2f_handlers[["%o%"]] <- function(
738826 stopifnot(length(args ) == 2L )
739827 x <- r2f(args [[1L ]], scope , ... , hoist = hoist )
740828 y <- r2f(args [[2L ]], scope , ... , hoist = hoist )
741- outer_mul(x , y , scope = scope , hoist = hoist , dest = dest )
829+ outer_mul(
830+ x ,
831+ y ,
832+ scope = scope ,
833+ hoist = hoist ,
834+ dest = dest ,
835+ context = " %o%"
836+ )
742837}
743838
744839r2f_handlers [[" forwardsolve" ]] <- function (
@@ -777,7 +872,8 @@ r2f_handlers[["forwardsolve"]] <- function(
777872 diag = if (diag_unit ) " U" else " N" ,
778873 scope = scope ,
779874 hoist = hoist ,
780- dest = dest
875+ dest = dest ,
876+ context = " forwardsolve"
781877 )
782878}
783879
@@ -807,7 +903,8 @@ r2f_handlers[["backsolve"]] <- function(
807903 diag = if (diag_unit ) " U" else " N" ,
808904 scope = scope ,
809905 hoist = hoist ,
810- dest = dest
906+ dest = dest ,
907+ context = " backsolve"
811908 )
812909}
813910
0 commit comments