blob: 4f5291b585f29e180cf1753d1bb625771bbf665f [file] [log] [blame]
Alexis Perry352d3472020-01-28 02:18:451//===-- runtime/transformational.cpp --------------------------------------===//
peter klauslera8fed822018-08-02 18:45:112//
Gary Klimowicz9e7548a2019-12-20 20:52:073// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
peter klauslera8fed822018-08-02 18:45:116//
Gary Klimowiczcea10402020-01-10 20:12:037//===----------------------------------------------------------------------===//
peter klauslera8fed822018-08-02 18:45:118
peter klauslerc1db35f2021-05-20 17:37:039// Implements the transformational intrinsic functions of Fortran 2018 that
10// rearrange or duplicate data without (much) regard to type. These are
11// CSHIFT, EOSHIFT, PACK, RESHAPE, SPREAD, TRANSPOSE, and UNPACK.
12//
13// Many of these are defined in the 2018 standard with text that makes sense
14// only if argument arrays have lower bounds of one. Rather than interpret
15// these cases as implying a hidden constraint, these implementations
16// work with arbitrary lower bounds. This may be technically an extension
17// of the standard but it more likely to conform with its intent.
18
Peter Klausler830c0b92021-09-01 23:00:5319#include "flang/Runtime/transformational.h"
peter klauslerc1db35f2021-05-20 17:37:0320#include "copy.h"
peter klausler3b635712020-02-13 22:41:5621#include "terminator.h"
peter klauslere372e0f2021-03-31 16:14:0822#include "tools.h"
peter klauslera8fed822018-08-02 18:45:1123#include <algorithm>
peter klauslera8fed822018-08-02 18:45:1124
25namespace Fortran::runtime {
26
peter klauslerc1db35f2021-05-20 17:37:0327// Utility for CSHIFT & EOSHIFT rank > 1 cases that determines the shift count
28// for each of the vector sections of the result.
29class ShiftControl {
30public:
31 ShiftControl(const Descriptor &s, Terminator &t, int dim)
32 : shift_{s}, terminator_{t}, shiftRank_{s.rank()}, dim_{dim} {}
33 void Init(const Descriptor &source) {
34 int rank{source.rank()};
35 RUNTIME_CHECK(terminator_, shiftRank_ == 0 || shiftRank_ == rank - 1);
36 auto catAndKind{shift_.type().GetCategoryAndKind()};
37 RUNTIME_CHECK(
38 terminator_, catAndKind && catAndKind->first == TypeCategory::Integer);
39 shiftElemLen_ = catAndKind->second;
40 if (shiftRank_ > 0) {
41 int k{0};
42 for (int j{0}; j < rank; ++j) {
43 if (j + 1 != dim_) {
44 const Dimension &shiftDim{shift_.GetDimension(k)};
45 lb_[k++] = shiftDim.LowerBound();
46 RUNTIME_CHECK(terminator_,
47 shiftDim.Extent() == source.GetDimension(j).Extent());
48 }
49 }
50 } else {
51 shiftCount_ =
52 GetInt64(shift_.OffsetElement<char>(), shiftElemLen_, terminator_);
53 }
54 }
55 SubscriptValue GetShift(const SubscriptValue resultAt[]) const {
56 if (shiftRank_ > 0) {
57 SubscriptValue shiftAt[maxRank];
58 int k{0};
59 for (int j{0}; j < shiftRank_ + 1; ++j) {
60 if (j + 1 != dim_) {
61 shiftAt[k] = lb_[k] + resultAt[j] - 1;
62 ++k;
63 }
64 }
65 return GetInt64(
66 shift_.Element<char>(shiftAt), shiftElemLen_, terminator_);
67 } else {
68 return shiftCount_; // invariant count extracted in Init()
69 }
70 }
71
72private:
73 const Descriptor &shift_;
74 Terminator &terminator_;
75 int shiftRank_;
76 int dim_;
77 SubscriptValue lb_[maxRank];
78 std::size_t shiftElemLen_;
79 SubscriptValue shiftCount_{};
80};
81
82// Fill an EOSHIFT result with default boundary values
83static void DefaultInitialize(
84 const Descriptor &result, Terminator &terminator) {
85 auto catAndKind{result.type().GetCategoryAndKind()};
86 RUNTIME_CHECK(
87 terminator, catAndKind && catAndKind->first != TypeCategory::Derived);
88 std::size_t elementLen{result.ElementBytes()};
89 std::size_t bytes{result.Elements() * elementLen};
90 if (catAndKind->first == TypeCategory::Character) {
91 switch (int kind{catAndKind->second}) {
92 case 1:
93 std::fill_n(result.OffsetElement<char>(), bytes, ' ');
94 break;
95 case 2:
96 std::fill_n(result.OffsetElement<char16_t>(), bytes / 2,
97 static_cast<char16_t>(' '));
98 break;
99 case 4:
100 std::fill_n(result.OffsetElement<char32_t>(), bytes / 4,
101 static_cast<char32_t>(' '));
102 break;
103 default:
104 terminator.Crash("EOSHIFT: bad CHARACTER kind %d", kind);
105 }
106 } else {
107 std::memset(result.raw().base_addr, 0, bytes);
108 }
109}
110
111static inline std::size_t AllocateResult(Descriptor &result,
112 const Descriptor &source, int rank, const SubscriptValue extent[],
113 Terminator &terminator, const char *function) {
114 std::size_t elementLen{source.ElementBytes()};
115 const DescriptorAddendum *sourceAddendum{source.Addendum()};
116 result.Establish(source.type(), elementLen, nullptr, rank, extent,
117 CFI_attribute_allocatable, sourceAddendum != nullptr);
118 if (sourceAddendum) {
119 *result.Addendum() = *sourceAddendum;
120 }
121 for (int j{0}; j < rank; ++j) {
122 result.GetDimension(j).SetBounds(1, extent[j]);
123 }
124 if (int stat{result.Allocate()}) {
125 terminator.Crash(
126 "%s: Could not allocate memory for result (stat=%d)", function, stat);
127 }
128 return elementLen;
129}
130
131extern "C" {
132
Peter Steinfeld7898e7c2021-07-19 18:22:45133// CSHIFT where rank of ARRAY argument > 1
peter klauslerc1db35f2021-05-20 17:37:03134void RTNAME(Cshift)(Descriptor &result, const Descriptor &source,
135 const Descriptor &shift, int dim, const char *sourceFile, int line) {
136 Terminator terminator{sourceFile, line};
137 int rank{source.rank()};
138 RUNTIME_CHECK(terminator, rank > 1);
139 RUNTIME_CHECK(terminator, dim >= 1 && dim <= rank);
140 ShiftControl shiftControl{shift, terminator, dim};
141 shiftControl.Init(source);
142 SubscriptValue extent[maxRank];
143 source.GetShape(extent);
144 AllocateResult(result, source, rank, extent, terminator, "CSHIFT");
145 SubscriptValue resultAt[maxRank];
146 for (int j{0}; j < rank; ++j) {
147 resultAt[j] = 1;
148 }
149 SubscriptValue sourceLB[maxRank];
150 source.GetLowerBounds(sourceLB);
151 SubscriptValue dimExtent{extent[dim - 1]};
152 SubscriptValue dimLB{sourceLB[dim - 1]};
153 SubscriptValue &resDim{resultAt[dim - 1]};
154 for (std::size_t n{result.Elements()}; n > 0; n -= dimExtent) {
155 SubscriptValue shiftCount{shiftControl.GetShift(resultAt)};
156 SubscriptValue sourceAt[maxRank];
157 for (int j{0}; j < rank; ++j) {
158 sourceAt[j] = sourceLB[j] + resultAt[j] - 1;
159 }
160 SubscriptValue &sourceDim{sourceAt[dim - 1]};
161 sourceDim = dimLB + shiftCount % dimExtent;
162 if (shiftCount < 0) {
163 sourceDim += dimExtent;
164 }
165 for (resDim = 1; resDim <= dimExtent; ++resDim) {
166 CopyElement(result, resultAt, source, sourceAt, terminator);
167 if (++sourceDim == dimLB + dimExtent) {
168 sourceDim = dimLB;
169 }
170 }
171 result.IncrementSubscripts(resultAt);
172 }
173}
174
Peter Steinfeld7898e7c2021-07-19 18:22:45175// CSHIFT where rank of ARRAY argument == 1
peter klauslerc1db35f2021-05-20 17:37:03176void RTNAME(CshiftVector)(Descriptor &result, const Descriptor &source,
177 std::int64_t shift, const char *sourceFile, int line) {
178 Terminator terminator{sourceFile, line};
179 RUNTIME_CHECK(terminator, source.rank() == 1);
180 const Dimension &sourceDim{source.GetDimension(0)};
181 SubscriptValue extent{sourceDim.Extent()};
182 AllocateResult(result, source, 1, &extent, terminator, "CSHIFT");
183 SubscriptValue lb{sourceDim.LowerBound()};
184 for (SubscriptValue j{0}; j < extent; ++j) {
185 SubscriptValue resultAt{1 + j};
186 SubscriptValue sourceAt{lb + (j + shift) % extent};
Jean Perier6544d9a42021-11-12 08:25:22187 if (sourceAt < lb) {
Peter Steinfeld7898e7c2021-07-19 18:22:45188 sourceAt += extent;
189 }
peter klauslerc1db35f2021-05-20 17:37:03190 CopyElement(result, &resultAt, source, &sourceAt, terminator);
191 }
192}
193
194// EOSHIFT of rank > 1
195void RTNAME(Eoshift)(Descriptor &result, const Descriptor &source,
196 const Descriptor &shift, const Descriptor *boundary, int dim,
197 const char *sourceFile, int line) {
198 Terminator terminator{sourceFile, line};
199 SubscriptValue extent[maxRank];
200 int rank{source.GetShape(extent)};
201 RUNTIME_CHECK(terminator, rank > 1);
202 RUNTIME_CHECK(terminator, dim >= 1 && dim <= rank);
203 std::size_t elementLen{
204 AllocateResult(result, source, rank, extent, terminator, "EOSHIFT")};
205 int boundaryRank{-1};
206 if (boundary) {
207 boundaryRank = boundary->rank();
208 RUNTIME_CHECK(terminator, boundaryRank == 0 || boundaryRank == rank - 1);
209 RUNTIME_CHECK(terminator,
210 boundary->type() == source.type() &&
211 boundary->ElementBytes() == elementLen);
212 if (boundaryRank > 0) {
213 int k{0};
214 for (int j{0}; j < rank; ++j) {
215 if (j != dim - 1) {
216 RUNTIME_CHECK(
217 terminator, boundary->GetDimension(k).Extent() == extent[j]);
218 ++k;
219 }
220 }
221 }
222 }
223 ShiftControl shiftControl{shift, terminator, dim};
224 shiftControl.Init(source);
225 SubscriptValue resultAt[maxRank];
226 for (int j{0}; j < rank; ++j) {
227 resultAt[j] = 1;
228 }
229 if (!boundary) {
230 DefaultInitialize(result, terminator);
231 }
232 SubscriptValue sourceLB[maxRank];
233 source.GetLowerBounds(sourceLB);
234 SubscriptValue boundaryAt[maxRank];
235 if (boundaryRank > 0) {
236 boundary->GetLowerBounds(boundaryAt);
237 }
238 SubscriptValue dimExtent{extent[dim - 1]};
239 SubscriptValue dimLB{sourceLB[dim - 1]};
240 SubscriptValue &resDim{resultAt[dim - 1]};
241 for (std::size_t n{result.Elements()}; n > 0; n -= dimExtent) {
242 SubscriptValue shiftCount{shiftControl.GetShift(resultAt)};
243 SubscriptValue sourceAt[maxRank];
244 for (int j{0}; j < rank; ++j) {
245 sourceAt[j] = sourceLB[j] + resultAt[j] - 1;
246 }
247 SubscriptValue &sourceDim{sourceAt[dim - 1]};
248 sourceDim = dimLB + shiftCount;
249 for (resDim = 1; resDim <= dimExtent; ++resDim) {
250 if (sourceDim >= dimLB && sourceDim < dimLB + dimExtent) {
251 CopyElement(result, resultAt, source, sourceAt, terminator);
252 } else if (boundary) {
253 CopyElement(result, resultAt, *boundary, boundaryAt, terminator);
254 }
255 ++sourceDim;
256 }
257 result.IncrementSubscripts(resultAt);
258 if (boundaryRank > 0) {
259 boundary->IncrementSubscripts(boundaryAt);
260 }
261 }
262}
263
264// EOSHIFT of vector
265void RTNAME(EoshiftVector)(Descriptor &result, const Descriptor &source,
266 std::int64_t shift, const Descriptor *boundary, const char *sourceFile,
267 int line) {
268 Terminator terminator{sourceFile, line};
269 RUNTIME_CHECK(terminator, source.rank() == 1);
270 SubscriptValue extent{source.GetDimension(0).Extent()};
271 std::size_t elementLen{
272 AllocateResult(result, source, 1, &extent, terminator, "EOSHIFT")};
peter klauslerc1db35f2021-05-20 17:37:03273 if (boundary) {
274 RUNTIME_CHECK(terminator, boundary->rank() == 0);
275 RUNTIME_CHECK(terminator,
276 boundary->type() == source.type() &&
277 boundary->ElementBytes() == elementLen);
278 }
279 if (!boundary) {
280 DefaultInitialize(result, terminator);
281 }
282 SubscriptValue lb{source.GetDimension(0).LowerBound()};
283 for (SubscriptValue j{1}; j <= extent; ++j) {
284 SubscriptValue sourceAt{lb + j - 1 + shift};
285 if (sourceAt >= lb && sourceAt < lb + extent) {
286 CopyElement(result, &j, source, &sourceAt, terminator);
Peter Steinfeldb8ecdcd2021-08-17 21:57:42287 } else if (boundary) {
288 CopyElement(result, &j, *boundary, 0, terminator);
peter klauslerc1db35f2021-05-20 17:37:03289 }
290 }
291}
292
293// PACK
294void RTNAME(Pack)(Descriptor &result, const Descriptor &source,
295 const Descriptor &mask, const Descriptor *vector, const char *sourceFile,
296 int line) {
297 Terminator terminator{sourceFile, line};
298 CheckConformability(source, mask, terminator, "PACK", "ARRAY=", "MASK=");
299 auto maskType{mask.type().GetCategoryAndKind()};
300 RUNTIME_CHECK(
301 terminator, maskType && maskType->first == TypeCategory::Logical);
302 SubscriptValue trues{0};
303 if (mask.rank() == 0) {
304 if (IsLogicalElementTrue(mask, nullptr)) {
305 trues = source.Elements();
306 }
307 } else {
308 SubscriptValue maskAt[maxRank];
309 mask.GetLowerBounds(maskAt);
310 for (std::size_t n{mask.Elements()}; n > 0; --n) {
311 if (IsLogicalElementTrue(mask, maskAt)) {
312 ++trues;
313 }
314 mask.IncrementSubscripts(maskAt);
315 }
316 }
317 SubscriptValue extent{trues};
318 if (vector) {
319 RUNTIME_CHECK(terminator, vector->rank() == 1);
320 RUNTIME_CHECK(terminator,
321 source.type() == vector->type() &&
322 source.ElementBytes() == vector->ElementBytes());
323 extent = vector->GetDimension(0).Extent();
324 RUNTIME_CHECK(terminator, extent >= trues);
325 }
326 AllocateResult(result, source, 1, &extent, terminator, "PACK");
327 SubscriptValue sourceAt[maxRank], resultAt{1};
328 source.GetLowerBounds(sourceAt);
329 if (mask.rank() == 0) {
330 if (IsLogicalElementTrue(mask, nullptr)) {
331 for (SubscriptValue n{trues}; n > 0; --n) {
332 CopyElement(result, &resultAt, source, sourceAt, terminator);
333 ++resultAt;
334 source.IncrementSubscripts(sourceAt);
335 }
336 }
337 } else {
338 SubscriptValue maskAt[maxRank];
339 mask.GetLowerBounds(maskAt);
340 for (std::size_t n{source.Elements()}; n > 0; --n) {
341 if (IsLogicalElementTrue(mask, maskAt)) {
342 CopyElement(result, &resultAt, source, sourceAt, terminator);
343 ++resultAt;
344 }
345 source.IncrementSubscripts(sourceAt);
346 mask.IncrementSubscripts(maskAt);
347 }
348 }
349 if (vector) {
350 SubscriptValue vectorAt{
351 vector->GetDimension(0).LowerBound() + resultAt - 1};
352 for (; resultAt <= extent; ++resultAt, ++vectorAt) {
353 CopyElement(result, &resultAt, *vector, &vectorAt, terminator);
354 }
355 }
356}
357
Mark Leaira1034022021-06-24 23:55:45358// RESHAPE
peter klauslera8fed822018-08-02 18:45:11359// F2018 16.9.163
Mark Leaira1034022021-06-24 23:55:45360void RTNAME(Reshape)(Descriptor &result, const Descriptor &source,
peter klauslerc1db35f2021-05-20 17:37:03361 const Descriptor &shape, const Descriptor *pad, const Descriptor *order,
362 const char *sourceFile, int line) {
peter klauslera8fed822018-08-02 18:45:11363 // Compute and check the rank of the result.
peter klauslerc1db35f2021-05-20 17:37:03364 Terminator terminator{sourceFile, line};
peter klausler3b635712020-02-13 22:41:56365 RUNTIME_CHECK(terminator, shape.rank() == 1);
366 RUNTIME_CHECK(terminator, shape.type().IsInteger());
peter klauslera8fed822018-08-02 18:45:11367 SubscriptValue resultRank{shape.GetDimension(0).Extent()};
peter klausler3b635712020-02-13 22:41:56368 RUNTIME_CHECK(terminator,
369 resultRank >= 0 && resultRank <= static_cast<SubscriptValue>(maxRank));
peter klauslera8fed822018-08-02 18:45:11370
371 // Extract and check the shape of the result; compute its element count.
peter klauslera8fed822018-08-02 18:45:11372 SubscriptValue resultExtent[maxRank];
373 std::size_t shapeElementBytes{shape.ElementBytes()};
374 std::size_t resultElements{1};
375 SubscriptValue shapeSubscript{shape.GetDimension(0).LowerBound()};
376 for (SubscriptValue j{0}; j < resultRank; ++j, ++shapeSubscript) {
peter klauslerc1db35f2021-05-20 17:37:03377 resultExtent[j] = GetInt64(
378 shape.Element<char>(&shapeSubscript), shapeElementBytes, terminator);
peter klausler3b635712020-02-13 22:41:56379 RUNTIME_CHECK(terminator, resultExtent[j] >= 0);
peter klauslera8fed822018-08-02 18:45:11380 resultElements *= resultExtent[j];
381 }
382
383 // Check that there are sufficient elements in the SOURCE=, or that
384 // the optional PAD= argument is present and nonempty.
peter klauslerfac96c42018-08-03 00:04:31385 std::size_t elementBytes{source.ElementBytes()};
peter klauslera8fed822018-08-02 18:45:11386 std::size_t sourceElements{source.Elements()};
387 std::size_t padElements{pad ? pad->Elements() : 0};
388 if (resultElements < sourceElements) {
peter klausler3b635712020-02-13 22:41:56389 RUNTIME_CHECK(terminator, padElements > 0);
390 RUNTIME_CHECK(terminator, pad->ElementBytes() == elementBytes);
peter klauslera8fed822018-08-02 18:45:11391 }
392
393 // Extract and check the optional ORDER= argument, which must be a
394 // permutation of [1..resultRank].
395 int dimOrder[maxRank];
peter klausler18f5ce52019-11-09 17:29:31396 if (order) {
peter klausler3b635712020-02-13 22:41:56397 RUNTIME_CHECK(terminator, order->rank() == 1);
398 RUNTIME_CHECK(terminator, order->type().IsInteger());
399 RUNTIME_CHECK(terminator, order->GetDimension(0).Extent() == resultRank);
400 std::uint64_t values{0};
peter klauslera8fed822018-08-02 18:45:11401 SubscriptValue orderSubscript{order->GetDimension(0).LowerBound()};
Mark Leaira1034022021-06-24 23:55:45402 std::size_t orderElementBytes{order->ElementBytes()};
peter klauslera8fed822018-08-02 18:45:11403 for (SubscriptValue j{0}; j < resultRank; ++j, ++orderSubscript) {
Mark Leaira1034022021-06-24 23:55:45404 auto k{GetInt64(order->Element<char>(&orderSubscript), orderElementBytes,
405 terminator)};
peter klausler3b635712020-02-13 22:41:56406 RUNTIME_CHECK(
407 terminator, k >= 1 && k <= resultRank && !((values >> k) & 1));
408 values |= std::uint64_t{1} << k;
peter klauslera8fed822018-08-02 18:45:11409 dimOrder[k - 1] = j;
410 }
411 } else {
412 for (int j{0}; j < resultRank; ++j) {
413 dimOrder[j] = j;
414 }
415 }
416
Mark Leaira1034022021-06-24 23:55:45417 // Allocate result descriptor
418 AllocateResult(
419 result, source, resultRank, resultExtent, terminator, "RESHAPE");
peter klauslera8fed822018-08-02 18:45:11420
421 // Populate the result's elements.
422 SubscriptValue resultSubscript[maxRank];
Mark Leaira1034022021-06-24 23:55:45423 result.GetLowerBounds(resultSubscript);
peter klauslera8fed822018-08-02 18:45:11424 SubscriptValue sourceSubscript[maxRank];
425 source.GetLowerBounds(sourceSubscript);
426 std::size_t resultElement{0};
427 std::size_t elementsFromSource{std::min(resultElements, sourceElements)};
428 for (; resultElement < elementsFromSource; ++resultElement) {
Mark Leaira1034022021-06-24 23:55:45429 CopyElement(result, resultSubscript, source, sourceSubscript, terminator);
peter klauslera8fed822018-08-02 18:45:11430 source.IncrementSubscripts(sourceSubscript);
Mark Leaira1034022021-06-24 23:55:45431 result.IncrementSubscripts(resultSubscript, dimOrder);
peter klauslera8fed822018-08-02 18:45:11432 }
433 if (resultElement < resultElements) {
434 // Remaining elements come from the optional PAD= argument.
435 SubscriptValue padSubscript[maxRank];
436 pad->GetLowerBounds(padSubscript);
437 for (; resultElement < resultElements; ++resultElement) {
Mark Leaira1034022021-06-24 23:55:45438 CopyElement(result, resultSubscript, *pad, padSubscript, terminator);
peter klauslera8fed822018-08-02 18:45:11439 pad->IncrementSubscripts(padSubscript);
Mark Leaira1034022021-06-24 23:55:45440 result.IncrementSubscripts(resultSubscript, dimOrder);
peter klauslera8fed822018-08-02 18:45:11441 }
442 }
peter klauslera8fed822018-08-02 18:45:11443}
peter klauslerc1db35f2021-05-20 17:37:03444
445// SPREAD
446void RTNAME(Spread)(Descriptor &result, const Descriptor &source, int dim,
447 std::int64_t ncopies, const char *sourceFile, int line) {
448 Terminator terminator{sourceFile, line};
449 int rank{source.rank() + 1};
450 RUNTIME_CHECK(terminator, rank <= maxRank);
451 ncopies = std::max<std::int64_t>(ncopies, 0);
452 SubscriptValue extent[maxRank];
453 int k{0};
454 for (int j{0}; j < rank; ++j) {
455 extent[j] = j == dim - 1 ? ncopies : source.GetDimension(k++).Extent();
456 }
457 AllocateResult(result, source, rank, extent, terminator, "SPREAD");
458 SubscriptValue resultAt[maxRank];
459 for (int j{0}; j < rank; ++j) {
460 resultAt[j] = 1;
461 }
462 SubscriptValue &resultDim{resultAt[dim - 1]};
463 SubscriptValue sourceAt[maxRank];
464 source.GetLowerBounds(sourceAt);
465 for (std::size_t n{result.Elements()}; n > 0; n -= ncopies) {
466 for (resultDim = 1; resultDim <= ncopies; ++resultDim) {
467 CopyElement(result, resultAt, source, sourceAt, terminator);
468 }
469 result.IncrementSubscripts(resultAt);
470 source.IncrementSubscripts(sourceAt);
471 }
472}
473
474// TRANSPOSE
475void RTNAME(Transpose)(Descriptor &result, const Descriptor &matrix,
476 const char *sourceFile, int line) {
477 Terminator terminator{sourceFile, line};
478 RUNTIME_CHECK(terminator, matrix.rank() == 2);
479 SubscriptValue extent[2]{
480 matrix.GetDimension(1).Extent(), matrix.GetDimension(0).Extent()};
481 AllocateResult(result, matrix, 2, extent, terminator, "TRANSPOSE");
482 SubscriptValue resultAt[2]{1, 1};
483 SubscriptValue matrixLB[2];
484 matrix.GetLowerBounds(matrixLB);
485 for (std::size_t n{result.Elements()}; n-- > 0;
486 result.IncrementSubscripts(resultAt)) {
487 SubscriptValue matrixAt[2]{
488 matrixLB[0] + resultAt[1] - 1, matrixLB[1] + resultAt[0] - 1};
489 CopyElement(result, resultAt, matrix, matrixAt, terminator);
490 }
491}
492
493// UNPACK
494void RTNAME(Unpack)(Descriptor &result, const Descriptor &vector,
495 const Descriptor &mask, const Descriptor &field, const char *sourceFile,
496 int line) {
497 Terminator terminator{sourceFile, line};
498 RUNTIME_CHECK(terminator, vector.rank() == 1);
499 int rank{mask.rank()};
500 RUNTIME_CHECK(terminator, rank > 0);
501 SubscriptValue extent[maxRank];
502 mask.GetShape(extent);
503 CheckConformability(mask, field, terminator, "UNPACK", "MASK=", "FIELD=");
504 std::size_t elementLen{
505 AllocateResult(result, field, rank, extent, terminator, "UNPACK")};
506 RUNTIME_CHECK(terminator,
507 vector.type() == field.type() && vector.ElementBytes() == elementLen);
508 SubscriptValue resultAt[maxRank], maskAt[maxRank], fieldAt[maxRank],
509 vectorAt{vector.GetDimension(0).LowerBound()};
510 for (int j{0}; j < rank; ++j) {
511 resultAt[j] = 1;
512 }
513 mask.GetLowerBounds(maskAt);
514 field.GetLowerBounds(fieldAt);
515 SubscriptValue vectorLeft{vector.GetDimension(0).Extent()};
516 for (std::size_t n{result.Elements()}; n-- > 0;) {
517 if (IsLogicalElementTrue(mask, maskAt)) {
518 if (vectorLeft-- == 0) {
519 terminator.Crash("UNPACK: VECTOR= argument has fewer elements than "
520 "MASK= has .TRUE. entries");
521 }
522 CopyElement(result, resultAt, vector, &vectorAt, terminator);
523 ++vectorAt;
524 } else {
525 CopyElement(result, resultAt, field, fieldAt, terminator);
526 }
527 result.IncrementSubscripts(resultAt);
528 mask.IncrementSubscripts(maskAt);
529 field.IncrementSubscripts(fieldAt);
530 }
531}
532
533} // extern "C"
Tim Keith1f879002020-03-29 04:00:16534} // namespace Fortran::runtime