-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcompileSApply.R
126 lines (106 loc) · 4.8 KB
/
compileSApply.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
getSApplyType =
# returns NULL if not a case we would rewrite an sapply()
# The intent here is when we are using the apply() idiom on an non-R object
# just for expressiveness.
function(call, env, funName = as.character(call[[1]])) {
if(funName %in% c("sapply", "lapply") && isSEXPType(type <- getDataType(call[[2]], env)) )
type
else
NULL
}
rewriteSApply =
#
# This rewrites a call to sapply() into a for loop, allocating the space for the answer, etc.
# This is used when the type of the first argument to the sapply() call is a SEXP and not
# a native array/pointer.
#
# The approach below doesn't compile the code directly, but
# rewrites the code so that we can use the existing facilities to compile it.
#
# See fgets.Rdb
#
# For now, ignore simplify and USE.NAMES. Assume they aren't there.
#
# If we know the types of the vector and the return type of the function,
# we can insert them now. Otherwise, we could use special functions that our
# "compiler" will know to replace
#
# When we compile this we need to know that INTEGER() maps to int *, etc.
# When we find these globals before we generate code, we need to register them.
#
# ty = getDataType(sym, env)
#
#
# unprotect the variable, not by count (1L)
# [test] when the R object being returned has direct element accessor (logical, integern, numeric)
# get the pointer for the array outside of the loop and use it.
#
function(call, vecType, returnType, addReturn = TRUE, env = NULL, ir = NULL, ...)
{
# returnType is the C-level return type of the function being sapply()'ed to each element, i.e. the FUN
X = call[[2]]
# get length of the R vector.
len = quote(n <- Rf_length(x))
len[[3]][[2]] = X # assume just a symbol
hasElsAccessor = !( is(vecType, "STRSXPType") || is(vecType, "VECSXPType"))
if(hasElsAccessor) {
# get the raw data for the elements. Doesn't work for character(). Need to call GET_STRING_ELT() within the loop.
els = quote(els <- foo(x))
els[[3]][[2]] = X
els[[3]][[1]] = as.name(getSEXPDataAccessor(vecType)) # get the INTEGER, REAL, etc. for the type
} else {
els = NULL
}
#XXX Could add the types for els and el right now.
# allocate answer
alloc = quote(r_ans <- Rf_allocVector(sexpEnum, n))
alloc[[3]][[2]] = sexpTypeNum = getSEXPTypeNum(returnType) # !!returnType) # get INTSXP, REALSXP, etc.
# create the instruction to get the element from X and assign it to el
funCall = quote(tmp <- f(el))
funCall[[3]][[1]] = call[[3]]
if(length(call) > 3) # dealing with extra arguments to our f()
funCall[[3]][seq(3, length = length(call) - 3)] = call[-(1:3)]
loop =
quote(for(i in 1:n) {
el = els[i]
x # replaced with f(el)
r_ans[i] = tmp # leave to the compiler make sense of this.
})
loop[[4]][[3]] = funCall
# Add the type for r_ans to the compiler's known types
# This might indicate that we have created that variable already
# So we may need to maintain a list of the variables we have explicitly
# allocated separately from the type information that we know ahead of time.
R.returnType = getSEXPType(names(sexpTypeNum))
if(!is.null(env))
#??? would class(vecType) work the same with the new classes
env$.types$r_ans = R.returnType
if(!hasElsAccessor) {
accessorFun = if(is(vecType, "STRSXPType")) "STRING_ELT" else "VECTOR_ELT"
loop[[4]][[2]][[3]] = substitute( f(x, i-1L), list( f = as.name(accessorFun), x = X ) )
}
# Fix up the assignment of the value tmp within the loop to the r_ans object
if(is(R.returnType, "VECSXPType") || is(R.returnType, "STRSXPType")) {
loop[[4]][[3]] = substitute(OP(r_ans, i - 1L, val), list(val = loop[[4]][[3]][[3]],
OP = if(is(R.returnType, "VECSXPType"))
as.name("SET_VECTOR_ELT")
else
as.name("SET_STRING_ELT")))
if(sameType(returnType, StringType))
loop[[4]][[3]][[4]] = substitute(Rf_mkChar(val), list(val = loop[[4]][[3]][[4]]))
loop[[4]] = loop[[4]][-4]
} else {
acc = getSEXPTypeElementAccessor(R.returnType)
alloc = list(alloc, substitute(r_ans_p <- ACC(r_ans), list(ACC = as.name(acc))))
loop[[4]][[4]][[2]] = quote( r_ans_p[i] )
}
ans = c(len,
els,
alloc,
quote(Rf_protect(r_ans)),
loop,
quote(Rf_unprotect(1L)),
if(addReturn)
quote(return(r_ans))
)
}