You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#defineIFORKEY 15 // special key support: like i.~, but add # values mapped to the index, and return #unique values in AM
659
-
#defineIINTER 16 // ([ -. -.)
659
+
#defineIINTER 16 // ([ -. -.) LSBs cause BIT arrays to init to 0 meaning 'don't keep'
660
+
#defineINUBIP 0x14 // ~. inplace LSBs cause BIT arrays to init to 1
660
661
#defineIIMODFIELD ((I)7<<IIOPMSKX) // bits used to indicate processing options
661
-
#defineIIMODPACKX 5
662
+
#defineIIMODPACKX 5 // must not exceed 5 since used in a shift
662
663
#defineIIMODPACK (((I)1)<<IIMODPACKX) // modifier for type. (small-range search except i./i:) In IIDOT/IICO, indicates reflexive application. In others, indicates that the
663
664
// bitmask should be stored as packed bits rather than bytes
664
665
#defineIIMODREFLEXX 5 // overlaps IIMODPACK; OK because reflexive i./i: needs to know where the match was & can't use bitmask
// ~. ~: I.@~. -. all prefer the table to be complemented and thus initialized to 1.
35
35
// REVERSED types always initialize to 1, whether packed or not
36
36
// this is a kludge - the initialization value should be passed in by the caller, in asct
37
-
UIfillval=md&IREVERSED?(md&IIMODPACK?255:1):((md&(IIMODPACK+IIOPMSK))<=INUBI); fillval|=fillval<<8; fillval|=fillval<<16; // mvc overfetches, so need full UI
38
-
mvc(p,hh->data.UI,4,&fillval); // fill with repeated copies of fillval
37
+
UIfillval= (((1LL<<INUBSV)|(1LL<<ILESS)|(1LL<<INUB)|(1LL<<INUBI)|(1LL<<INUBIP))>>(md&(IIMODPACK+IIOPMSK)))&1; UItemp=md&IIMODPACK?255:1; fillval=md&IREVERSED?temp:fillval; // mvc overfetches, so need full UI. If PACK, always 0; otherwise look at bits 0-3 of opcode
38
+
// obsolete UI fillval = md&IREVERSED?(md&IIMODPACK?255:1):((md&(IIMODPACK+IIOPMSKINIT))<=INUBI); // mvc overfetches, so need full UI. If PACK, always 0; otherwise look at bits 0-3 of opcode
Izt; Az; // type of result to allocate; address of block
768
770
if((mode&IIOPMSK)==IEPS)zt=B01;
769
771
else{
770
-
if(likely(a!=w)&&(at&INT+SY_64*FL)&-(SGNTO0(AC(w))&(I)jtinplace)){z=w; goto inplace;} // if inplaceable (not including assignment) and items have the right size
772
+
if(likely(a!=w)&&(at&INT+SY_64*FL)&-(SGNTO0(AC(w))&((I)jtinplace>>JTINPLACEWX))){z=w; goto inplace;} // if inplaceable (not including assignment) and items have the right size
771
773
zt=INT; // the result type depends on the operation.
772
774
}
773
775
GA(z,zt,wn,wr,AS(w)); // allocate result area
@@ -1064,22 +1066,33 @@ inplace:;
1064
1066
AFifn=fntbl[FNTABLEPREFIX+fnx][bighash]; // get an early start fetching the function we will call
1065
1067
1066
1068
// Allocate the result area. NOTE that some of the routines, like small-range, always store at least one result; so we have to point z somewhere harmless before launching them. If we are prehashing we skip this.
1067
-
// If the conditions are right, perform the operation inplace
1068
-
Az;
1069
+
// If the conditions are right, perform the operation inplace.
1070
+
Az;// will hold result
1069
1071
switch(mode&(IPHCALC|IIOPMSK)){
1070
1072
default: fauxINT(z,zfaux,1,0) break; // if prehashed, we must create an area that can hold at least one stored result
1071
-
caseIIDOT: caseIFORKEY:
1072
-
caseIICO: GATV0(z,INT,zn,f+f1); MCISH(AS(z),s,f) MCISH(f+AS(z),ws+wf,f1); break; // mustn't overfetch s
1073
+
caseIIDOT:
1074
+
caseIICO:
1075
+
// i./i: can run inplace on w if w is abandoned, not the same block as a, rank matches rank needed, item size<=SZI, DIRECT, and (not UNINCORPABLE or same type as result)
1076
+
if(likely(a!=w)&&likely(!(AFLAG(w)&AFUNINCORPABLE+AFRO))&&(-(AT(w)&(INT+SY_64*FL))&AC(w)&SGNIF(jtinplace,JTINPLACEWX)&((AR(w)^(f+f1))-1))<0){z=w; AT(z)=INT; break;} // inplace w if not disqualified
1077
+
// if can't inplace fall through to...
1078
+
caseIFORKEY:
1079
+
GATV0(z,INT,zn,f+f1); MCISH(AS(z),s,f) MCISH(f+AS(z),ws+wf,f1); break; // mustn't overfetch s
1080
+
caseILESS: caseIINTER:
1081
+
// -./([-.-.) can run inplace if w is abandoned, not the same block as a, rank not 0, DIRECT, not UNINCORPABLE (since we don't want to change shape of an unincorpable)
1082
+
if(likely(a!=w)&&likely(!(AFLAG(w)&AFUNINCORPABLE+AFRO))&&(((AT(w)&~DIRECT)-1)&AC(w)&SGNIF(jtinplace,JTINPLACEWX)&-(AR(w)))<0){z=w; break;} // inplace w if not disqualified
1083
+
ws=wr==0?&AN(w):ws; GA(z,AT(w),AN(w),MAX(1,wr),ws); break; // if wr is an atom, use 1 for the shape
1084
+
caseINUB:
1085
+
// ~. can run inplace if abandoned, rank>0, DIRECT
1086
+
if(likely(!(AFLAG(w)&AFUNINCORPABLE+AFRO))&&(((AT(w)&~DIRECT)-1)&AC(w)&SGNIF(jtinplace,JTINPLACEWX)&-(AR(w)))<0){z=w; mode^=INUB^INUBIP; break;} // inplace w if not disqualified
1087
+
{Iq; PRODX(q,AR(a)-1,AS(a)+1,MIN(m,p+1)) GA(z,t,q,MAX(1,wr),ws); break;} // we speculatively overwrite, possibly 1 more than in a but no more than in w
1088
+
caseINUBI: GATV0(z,INT,MIN(m,p)+1,1); break; // we speculatively overwrite but never past a full buffer
1073
1089
caseINUBSV: GATV0(z,B01,zn,f+f1+!acr); MCISH(AS(z),s,f) MCISH(f+AS(z),ws+wf,f1); if(!acr)AS(z)[AR(z)-1]=1; break; // mustn't overfetch s
1074
-
caseINUB: {Iq; PRODX(q,AR(a)-1,AS(a)+1,MIN(m,p)+1) GA(z,t,q,MAX(1,wr),ws); break;} // +1 because we speculatively overwrite.
1075
-
caseILESS: caseIINTER: ws=wr==0?&AN(w):ws; GA(z,AT(w),AN(w),MAX(1,wr),ws); break; // if wr is an atom, use 1 for the shape
// ([: I. e.) ([: +/ e.) ([: +./ e.) ([: *./ e.) come here only if e. produces rank 0 or 1.
1082
-
caseIIFBEPS: GATV0(z,INT,c+1,1); break; // +1 because we speculatively overwrite
1095
+
caseIIFBEPS: GATV0(z,INT,c,1); break; // we speculatively overwrite but not past a full buffer
1083
1096
caseIANYEPS: caseIALLEPS:
1084
1097
GAT0(z,B01,1,0); break;
1085
1098
caseISUMEPS:
@@ -1099,7 +1112,7 @@ inplace:;
1099
1112
caseIFORKEY: {z=reshape(shape(z),take(sc(m),sc(m))); RZ(z=mkwris(z)); AM(z)=!!m; Rz;} // all 0 but the first has the total count. Must install # partitions=1 if #items>0
if(unlikely((SGNIFSPARSE(AT(w))|SGNIF(AFLAG(w),AFNJAX))<0))Rrepeat(nubsieve(w),w); // sparse or NJA
1223
-
Az; RZ(z=indexofsub(INUB,w,w));
1236
+
Az; RZ(z=jtindexofsub(jtinplace,INUB,w,w));
1224
1237
// We extracted from w, so mark it (or its backer if virtual) non-pristine. If w was pristine and inplaceable, transfer its pristine status to the result. We overwrite w because it is no longer in use
// We extracted from a, so mark it (or its backer if virtual) non-pristine. If a was pristine and inplaceable, transfer its pristine status to the result
1243
1256
PRISTXFERAF(x,a)
1244
1257
RETF(x);
1245
1258
} /* a-.w */
1246
1259
1247
-
// x ([ -. -.[!.f]) y. does not have IRS
1260
+
// x ([ -. -.[!.f]) y. does not have IRS, supports inplacing
// Calculate the hash slot. The hash calculation (input parm) relies on the name v and produces the name j. We have moved v to an xmm register to reduce register pressure
@@ -78,11 +79,12 @@
78
79
// If (store) is 1, the value of i (which is the loop index giving the position within a of the item being processed) is stored into the empty hash slot,
79
80
// only if the hash search does not find a match. If (store) is 2, the entry that we found is cleared, by setting it to maxcount+1, when we find a match.
80
81
// When (store)=2, we also ignore hash entries containing maxcount+1, treating them as failed compares
82
+
// (store)=3 is ~. inplace:
81
83
// Independent of (store), (fstmt) is executed if the item is found in the hash table, and (nfstmt) is executed if it is not found.
if(unlikely(--name<0))name+=p; hj=hv[name]; /* miscompare, must continue search */ \
86
88
}while(1);
87
89
88
90
// Traverse the hash table for one argument. (src) indicates which argument, a or w, we are looping through; (hsrc) indicates which argument provided the hash table.
@@ -92,6 +94,7 @@
92
94
// q+2 is being calculated).
93
95
// The (fstmt,nfstmt,store) arguments indicate what to do when a match/notmatch is resolved.
94
96
// (loopctl) give the stride through the input array, the control for the main loop, and the index of the last value. These values differ for forward and reverse scans through the input.
97
+
// in the loop i is the index of the item being looked up in the hash (if store is not 0 or 3, that will be the index stored into the hashtable on notfound)
// Traverse w in forward direction, executing fstmt/nfstmt depending on found/notfound; and adding to the hash if (reflex) is 1, indicating a reflexive operation
106
+
// Traverse w in forward direction, executing fstmt/nfstmt depending on found/notfound; and adding to the hash if (reflex) is 1, indicating a reflexive operation scaf could save a register if reflexive
0 commit comments