//======================= int_div.cvl ====================== $system[civlc] void $assert(_Bool expr, ...); $system[int_div] int $remainder(int x, int y); $system[int_div] int $quotient(int x, int y); int $int_div(int numerator, int denominator) { $assert(denominator != 0, "Possible division by zero"); if (numerator == 0) return 0; if (numerator >= 0) { if (denominator >= 0) { int $sef$0 = $quotient(numerator, denominator); return $sef$0; } else { int $sef$1 = $quotient(numerator, -denominator); return -$sef$1; } } else { if (denominator >= 0) { int $sef$2 = $quotient(-numerator, denominator); return -$sef$2; } else { int $sef$3 = $quotient(-numerator, -denominator); return $sef$3; } } } //=================== unsigned_arith.cvl =================== int $signed_to_unsigned(int x, int bound) { if (x >= 0) { if (x < bound) return x; else { int $sef$9 = $remainder(x, bound); return $sef$9; } } else { if ((-x) <= bound) return bound + x; else { int $sef$10 = $remainder(-x, bound); return bound - $sef$10; } } } //======================= sum_array.c ====================== $input int _civl_argc; $system[civlc] void $assume(_Bool expression); $assume(0 < _civl_argc); $input char _civl_argv[_civl_argc][]; //======================== civlc.cvh ======================= typedef struct $scope $scope; /*@ depends_on \nothing; @ executes_when $true; @*/ $system[civlc] void* $malloc($scope s, int size); typedef unsigned long size_t; typedef struct $proc $proc; typedef struct $state $state; /*@ depends_on \nothing; @ executes_when $true; @*/ $system[civlc] void $assert(_Bool expr, ...); /*@ depends_on \nothing; @ executes_when $true; @*/ $system[civlc] void $assume(_Bool expr); /*@ depends_on \access(p); @ executes_when $true; @*/ $system[civlc] void $free(void* p); //========================== mpi.h ========================= typedef enum MPI_Datatype{ MPI_CHAR=0, MPI_CHARACTER=1, MPI_SIGNED_CHAR, MPI_UNSIGNED_CHAR, MPI_BYTE=2, MPI_WCHAR, MPI_SHORT=3, MPI_UNSIGNED_SHORT, MPI_INT=4, MPI_INT16_T, MPI_INT32_T, MPI_INT64_T, MPI_INT8_T, MPI_INTEGER, MPI_INTEGER1, MPI_INTEGER16, MPI_INTEGER2, MPI_INTEGER4, MPI_INTEGER8, MPI_UNSIGNED, MPI_LONG=5, MPI_UNSIGNED_LONG, MPI_FLOAT=9, MPI_DOUBLE=10, MPI_LONG_DOUBLE=11, MPI_LONG_LONG_INT=6, MPI_UNSIGNED_LONG_LONG=7, MPI_LONG_LONG=8, MPI_PACKED, MPI_LB, MPI_UB, MPI_UINT16_T, MPI_UINT32_T, MPI_UINT64_T, MPI_UINT8_T, MPI_FLOAT_INT, MPI_DOUBLE_INT, MPI_LONG_INT, MPI_SHORT_INT, MPI_2INT=12, MPI_LONG_DOUBLE_INT, MPI_AINT, MPI_OFFSET, MPI_2DOUBLE_PRECISION, MPI_2INTEGER, MPI_2REAL, MPI_C_BOOL, MPI_C_COMPLEX, MPI_C_DOUBLE_COMPLEX, MPI_C_FLOAT_COMPLEX, MPI_C_LONG_DOUBLE_COMPLEX, MPI_COMPLEX, MPI_COMPLEX16, MPI_COMPLEX32, MPI_COMPLEX4, MPI_COMPLEX8, MPI_REAL, MPI_REAL16, MPI_REAL2, MPI_REAL4, MPI_REAL8 } MPI_Datatype; //======================= sum_array.c ====================== $input long NB = 20; $input long N; $assume((0 < N) && (N <= NB)); //========================= seq.cvh ======================== /*@ depends_on \access(array); @ executes_when $true; @*/ $system[seq] int $seq_length(void* array); /*@ depends_on \access(array, value); @ executes_when $true; @*/ $system[seq] void $seq_init(void* array, int count, void* value); /*@ depends_on \access(array, values); @ executes_when $true; @*/ $system[seq] void $seq_insert(void* array, int index, void* values, int count); /*@ depends_on \access(array, values); @*/ $atomic_f void $seq_append(void* array, void* values, int count); //======================= bundle.cvh ======================= typedef struct _bundle $bundle; /*@ depends_on \access(ptr); @ executes_when $true; @*/ $system[bundle] $bundle $bundle_pack(const void* ptr, int size); /*@ depends_on \access(ptr); @ executes_when $true; @*/ $system[bundle] void $bundle_unpack($bundle bundle, void* ptr); //===================== concurrency.cvh ==================== typedef struct _gbarrier* $gbarrier; typedef struct _barrier* $barrier; /*@ depends_on \nothing; @ assigns \nothing; @ reads \nothing; @*/ $atomic_f $gbarrier $gbarrier_create($scope scope, int size); /*@ depends_on \access(gbarrier); @ reads \nothing; @ assigns gbarrier; @*/ $atomic_f void $gbarrier_destroy($gbarrier gbarrier); /*@ depends_on \nothing; @ assigns gbarrier; @ reads gbarrier; @*/ $atomic_f $barrier $barrier_create($scope scope, $gbarrier gbarrier, int place); /*@ depends_on \access(barrier); @ assigns barrier; @ reads \nothing; @*/ $atomic_f void $barrier_destroy($barrier barrier); //======================== comm.cvh ======================== typedef struct _message{ int source; int dest; int tag; $bundle data; int size; } $message; typedef struct _queue $queue; typedef struct _gcomm* $gcomm; typedef struct _comm* $comm; /*@ depends_on \access(data); @ executes_when $true; @*/ $atomic_f $message $message_pack(int source, int dest, int tag, void* data, int size); /*@ depends_on \nothing; @ executes_when $true; @*/ $atomic_f int $message_source($message message); /*@ depends_on \nothing; @ executes_when $true; @*/ $atomic_f int $message_tag($message message); /*@ depends_on \nothing; @ executes_when $true; @*/ $atomic_f int $message_dest($message message); /*@ depends_on \nothing; @ executes_when $true; @*/ $atomic_f int $message_size($message message); /*@ depends_on \access(buf); @ executes_when $true; @*/ $atomic_f void $message_unpack($message message, void* buf, int size); /*@ depends_on \nothing; @ assigns \nothing; @ reads \nothing; @*/ $atomic_f $gcomm $gcomm_create($scope scope, int size); /*@ depends_on \access(junkMsgs), \access(gcomm); @ assigns junkMsgs, gcomm; @*/ $atomic_f int $gcomm_destroy($gcomm gcomm, void* junkMsgs); /*@ depends_on \nothing; @ reads gcomm; @ assigns gcomm; @*/ $atomic_f $comm $comm_create($scope scope, $gcomm gcomm, int place); /*@ depends_on \access(comm); @ assigns comm; @ reads \nothing; @*/ $atomic_f void $comm_destroy($comm comm); /*@ depends_on \nothing; @*/ $atomic_f int $comm_size($comm comm); /*@ depends_on \nothing; @ executes_when $true; @*/ $atomic_f int $comm_place($comm comm); /*@ depends_on \access(comm); @ executes_when $true; @*/ $system[comm] void $comm_enqueue($comm comm, $message message); /*@ depends_on \access(comm); @ executes_when $true; @*/ $system[comm] $state_f _Bool $comm_probe($comm comm, int source, int tag); /*@ depends_on \access(comm); @ executes_when $comm_probe(comm, source, tag); @*/ $system[comm] $message $comm_dequeue($comm comm, int source, int tag); //======================= collate.cvh ====================== typedef struct _gcollator* $gcollator; typedef struct _collator* $collator; typedef struct _gcollate_state* $gcollate_state; $atomic_f $gcollator $gcollator_create($scope scope, int nprocs); $atomic_f $collator $collator_create($gcollator gcollator, $scope scope, int place); //====================== civl-mpi.cvh ====================== typedef struct $mpi_gcomm $mpi_gcomm; $mpi_gcomm $mpi_gcomm_create($scope, int); void $mpi_gcomm_destroy($mpi_gcomm); //========================= seq.cvl ======================== $atomic_f void $seq_append(void* array, void* values, int count) { int length = $seq_length(array); $seq_insert(array, length, values, count); } //===================== concurrency.cvl ==================== struct _gbarrier{ int nprocs; $proc proc_map[]; _Bool in_barrier[]; int num_in_barrier; }; struct _barrier{ int place; $gbarrier gbarrier; }; $atomic_f $gbarrier $gbarrier_create($scope scope, int size) { $gbarrier gbarrier = ($gbarrier)($malloc(scope, sizeof(struct _gbarrier))); (gbarrier)->nprocs = size; (gbarrier)->proc_map = (($proc[size]) $lambda (int i) $proc_null); (gbarrier)->in_barrier = ((_Bool[size]) $lambda (int i) 0); (gbarrier)->num_in_barrier = 0; return gbarrier; } $atomic_f void $gbarrier_destroy($gbarrier gbarrier) { $free(gbarrier); } $atomic_f $barrier $barrier_create($scope scope, $gbarrier gbarrier, int place) { $assert(((gbarrier)->proc_map[place]) == $proc_null, "the place %d in the global barrier has already been taken.", place); $barrier barrier = ($barrier)($malloc(scope, sizeof(struct _barrier))); (barrier)->place = place; (barrier)->gbarrier = gbarrier; (gbarrier)->proc_map[place] = $self; return barrier; } $atomic_f void $barrier_destroy($barrier barrier) { $free(barrier); } //====================== civl-mpi.cvl ====================== char* $mpi_coroutine_name(int tag); struct $mpi_gcomm{ $gcomm p2p; $gcomm col; $gcollator gcollator; $gbarrier gbarrier; }; $mpi_gcomm $mpi_gcomm_create($scope scope, int size) { $mpi_gcomm result; result.p2p = $gcomm_create(scope, size); result.col = $gcomm_create(scope, size); result.gcollator = $gcollator_create(scope, size); result.gbarrier = $gbarrier_create(scope, size); return result; } void $mpi_gcomm_destroy($mpi_gcomm gc) { int numJunkMsg; $message junkMsgs[]; $seq_init(&(junkMsgs), 0, (void*)0); numJunkMsg = $gcomm_destroy(gc.p2p, &(junkMsgs)); { int i = 0; for (; i < numJunkMsg; i = i + 1) { int src; int dest; int tag; src = $message_source(junkMsgs[i]); dest = $message_dest(junkMsgs[i]); tag = $message_tag(junkMsgs[i]); $assert(0, "MPI message leak: There is a message from rank %d to rank %d with tag %d has been sent but is never received in point-to-point communication.", src, dest, tag); } } numJunkMsg = $gcomm_destroy(gc.col, &(junkMsgs)); { int i = 0; for (; i < numJunkMsg; i = i + 1) { int src; int tag; char* routine; src = $message_source(junkMsgs[i]); tag = $message_tag(junkMsgs[i]); routine = $mpi_coroutine_name(tag); $assert(0, "MPI message leak: There is a message sent by rank %d for collective routine %s that is never received.", src, routine); } } $free(gc.gcollator); $gbarrier_destroy(gc.gbarrier); } char* $mpi_coroutine_name(int tag) { switch (tag) { case 9999: return "MPI_Bcast"; case 9998: return "MPI_Reduce"; case 9997: return "MPI_Allreduce"; case 9996: return "MPI_Gather"; case 9995: return "MPI_Scatter"; case 9994: return "MPI_Gatherv"; case 9993: return "MPI_Scatterv"; case 9992: return "MPI_Allgather"; case 9991: return "MPI_Reduce_scatter"; case 9990: return "MPI_Alltoall"; case 9989: return "MPI_Alltoallv"; case 9988: return "MPI_Alltoallw"; case 9987: return "MPI_Barrier"; case 9986: return "MPI_Commdup"; case 9985: return "MPI_Commfree"; default: $assert(0, "Internal Error: Unexpected MPI routine tag:%d.\n", tag); } } //======================== comm.cvl ======================== struct _queue{ int length; $message messages[]; }; struct _gcomm{ int nprocs; $proc procs[]; _Bool isInit[]; $queue buf[][]; }; struct _comm{ int place; $gcomm gcomm; }; $atomic_f $message $message_pack(int source, int dest, int tag, void* data, int size) { $message result; result.source = source; result.dest = dest; result.tag = tag; if ((data != (void*)0) && (size > 0)) { result.data = $bundle_pack(data, size); } else if (data == (void*)0) $assert(size == 0, "Attempt to pack a non-zero size message with a NULL pointer"); result.size = size; return result; } int $message_source($message message) { return message.source; } int $message_tag($message message) { return message.tag; } int $message_dest($message message) { return message.dest; } int $message_size($message message) { return message.size; } $atomic_f void $message_unpack($message message, void* buf, int size) { if ((buf != (void*)0) && (message.size > 0)) { $bundle_unpack(message.data, buf); $assert(message.size <= size, "Message of size %d exceeds the specified size %d.", message.size, size); } else if (buf == (void*)0) $assert(message.size == 0, "Attempt to unpack a non-zero size message with a NULL pointer."); } $atomic_f $gcomm $gcomm_create($scope scope, int size) { $gcomm gcomm = ($gcomm)($malloc(scope, sizeof(struct _gcomm))); $queue empty; empty.length = 0; $seq_init(&(empty.messages), 0, (void*)0); (gcomm)->nprocs = size; (gcomm)->procs = (($proc[size]) $lambda (int i) $proc_null); (gcomm)->isInit = ((_Bool[size]) $lambda (int i) 0); (gcomm)->buf = (($queue[size][size]) $lambda (int i, j) empty); return gcomm; } $atomic_f int $gcomm_destroy($gcomm gcomm, void* junkMsgs) { int nprocs = (gcomm)->nprocs; int numJunks = 0; if (junkMsgs != (void*)0) { { int i = 0; for (; i < nprocs; i = i + 1) { int j = 0; for (; j < nprocs; j = j + 1) { $queue queue = (gcomm)->buf[i][j]; if (queue.length > 0) $seq_append(junkMsgs, queue.messages, queue.length); } } } numJunks = $seq_length(junkMsgs); } $free(gcomm); return numJunks; } $atomic_f $comm $comm_create($scope scope, $gcomm gcomm, int place) { $assert(!((gcomm)->isInit[place]), "the place %d is already occupied in the global communicator!", place); $comm comm = ($comm)($malloc(scope, sizeof(struct _comm))); (gcomm)->procs[place] = $self; (gcomm)->isInit[place] = 1; (comm)->gcomm = gcomm; (comm)->place = place; return comm; } $atomic_f void $comm_destroy($comm comm) { $free(comm); } $atomic_f int $comm_place($comm comm) { return (comm)->place; } $atomic_f int $comm_size($comm comm) { return ((comm)->gcomm)->nprocs; } //======================= collate.cvl ====================== struct _gcollator{ int nprocs; $proc procs[]; int queue_length; $gcollate_state queue[]; _Bool entered[]; }; struct _collator{ int place; $gcollator gcollator; }; struct _gcollate_state{ int status[]; $state state; $bundle attribute; }; $gcollator $gcollator_create($scope scope, int nprocs) { $gcollator gcollator = ($gcollator)($malloc(scope, sizeof(struct _gcollator))); (gcollator)->nprocs = nprocs; (gcollator)->procs = (($proc[nprocs]) $lambda (int i) $proc_null); (gcollator)->queue_length = 0; $seq_init(&((gcollator)->queue), 0, (void*)0); (gcollator)->entered = ((_Bool[nprocs]) $lambda (int i) 0); return gcollator; } $collator $collator_create($gcollator gcollator, $scope scope, int place) { $collator collator = ($collator)($malloc(scope, sizeof(struct _collator))); (collator)->place = place; (collator)->gcollator = gcollator; ((collator)->gcollator)->procs[place] = $self; return collator; } //===================== MPITransformer ===================== $input int _mpi_nprocs; $input int _mpi_nprocs_lo = 1; //======================= sum_array.c ====================== $input int _mpi_nprocs_hi = 8; //===================== MPITransformer ===================== $assume((_mpi_nprocs_lo <= _mpi_nprocs) && (_mpi_nprocs <= _mpi_nprocs_hi)); $scope _mpi_root = $here; $mpi_gcomm _mpi_gcomm; $mpi_gcomm _mpi_gcomms[]; void _mpi_process(int _mpi_rank) { /*@ depends_on \access(format); @ executes_when $true; @*/ $system[stdio] int printf(char* restrict format, ...); typedef struct MPI_Comm MPI_Comm; MPI_Comm $mpi_comm_create($scope, $mpi_gcomm, int); MPI_Comm MPI_COMM_WORLD = $mpi_comm_create($here, _mpi_gcomm, _mpi_rank); typedef struct MPI_Status{ int MPI_SOURCE; int MPI_TAG; int MPI_ERROR; int size; } MPI_Status; int MPI_Send(void*, int, MPI_Datatype, int, int, MPI_Comm); int MPI_Recv(void*, int, MPI_Datatype, int, int, MPI_Comm, MPI_Status*); int MPI_Get_count(MPI_Status*, MPI_Datatype, int*); int MPI_Comm_size(MPI_Comm, int*); int MPI_Comm_rank(MPI_Comm, int*); typedef enum _mpi_state{ _MPI_UNINIT, _MPI_INIT, _MPI_FINALIZED } $mpi_state; $mpi_state _mpi_state = _MPI_UNINIT; int $mpi_init(void) { $assert(_mpi_state == _MPI_UNINIT, "Process can only call MPI_Init() at most once."); _mpi_state = _MPI_INIT; return 0; } void $mpi_comm_destroy(MPI_Comm, $mpi_state); int MPI_Finalize(void); double oracle; void master(void); void slave(void); int _civl_main(int argc, char** argv) { int myrank; $mpi_init(); MPI_Comm_rank(MPI_COMM_WORLD, &(myrank)); if (!myrank) master(); else slave(); MPI_Finalize(); return 0; } void master(void) { float array[N]; double mysum; double tmpsum; unsigned long long step; unsigned long long i; int size; MPI_Status status; for (i = $signed_to_unsigned(0, 4294967296); i < N; i = i + 1) { unsigned long long $sef$12 = $signed_to_unsigned(1, 4294967296); array[i] = i + $sef$12; } oracle = 0.0; for (i = $signed_to_unsigned(0, 4294967296); i < N; i = i + 1) oracle = oracle + (array[i]); MPI_Comm_size(MPI_COMM_WORLD, &(size)); if (size != 1) step = $int_div(N, size - 1); else step = N; for (i = $signed_to_unsigned(0, 4294967296); i < (size - 1); i = i + 1) { unsigned long long $sef$13 = $signed_to_unsigned(1, 4294967296); MPI_Send(array + (i * step), step, MPI_FLOAT, i + $sef$13, 100, MPI_COMM_WORLD); } { i = (size - 1) * step; mysum = 0; for (; i < N; i = i + 1) mysum = mysum + (array[i]); } for (i = $signed_to_unsigned(1, 4294967296); 1; ) { unsigned long long $sef$14 = $signed_to_unsigned(size, 4294967296); if (!(i < $sef$14)) break; MPI_Recv(&(tmpsum), 1, MPI_DOUBLE, -1, 101, MPI_COMM_WORLD, &(status)); mysum = mysum + tmpsum; i = i + 1; } $assert(oracle == mysum, "The sum of %d array elements is %f but the expected one is %f.\n", N, mysum, oracle); printf("%lf\n", mysum); } void slave(void) { float array[N]; double sum; unsigned long long i; int count; MPI_Status status; MPI_Recv(array, N, MPI_FLOAT, 0, 100, MPI_COMM_WORLD, &(status)); MPI_Get_count(&(status), MPI_FLOAT, &(count)); { i = $signed_to_unsigned(0, 4294967296); sum = 0; for (; 1; i = i + 1) { unsigned long long $sef$15 = $signed_to_unsigned(count, 4294967296); if (!(i < $sef$15)) break; sum = sum + (array[i]); } } MPI_Send(&(sum), 1, MPI_DOUBLE, 0, 101, MPI_COMM_WORLD); } /*@ depends_on \nothing; @ executes_when $true; @*/ $atomic_f $state_f int sizeofDatatype(MPI_Datatype); int $mpi_send(void*, int, MPI_Datatype, int, int, MPI_Comm); int $mpi_recv(void*, int, MPI_Datatype, int, int, MPI_Comm, MPI_Status*); /*@ depends_on \access(buf); @ executes_when $true; @*/ $system[mpi] void $mpi_check_buffer(void* buf, int count, MPI_Datatype datatype); struct MPI_Comm{ $comm p2p; $comm col; $collator collator; $barrier barrier; int gcommIndex; }; int MPI_Finalize(void) { $assert(_mpi_state == _MPI_INIT, "Process can only call MPI_Finalize() after the MPI enviroment is created and before cleaned."); _mpi_state = _MPI_FINALIZED; return 0; } int MPI_Comm_size(MPI_Comm comm, int* size) { $assert(_mpi_state == _MPI_INIT, "MPI_Comm_size() cannot be invoked without MPI_Init() being called before.\n"); *size = $comm_size(comm.p2p); return 0; } int MPI_Comm_rank(MPI_Comm comm, int* rank) { $assert(_mpi_state == _MPI_INIT, "MPI_Comm_rank() cannot be invoked without MPI_Init() being called before.\n"); *rank = $comm_place(comm.p2p); return 0; } int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) { $assert(_mpi_state == _MPI_INIT, "MPI_Send() cannot be invoked without MPI_Init() being called before.\n"); $mpi_check_buffer(buf, count, datatype); int $sef$16 = $mpi_send(buf, count, datatype, dest, tag, comm); return $sef$16; } int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status* status) { $assert(_mpi_state == _MPI_INIT, "MPI_Recv() cannot be invoked without MPI_Init() being called before.\n"); int $sef$17 = $mpi_recv(buf, count, datatype, source, tag, comm, status); return $sef$17; } int MPI_Get_count(MPI_Status* status, MPI_Datatype datatype, int* count) { $assert(_mpi_state == _MPI_INIT, "MPI_Get_count() cannot be invoked without MPI_Init() being called before.\n"); int $sef$18 = sizeofDatatype(datatype); *count = $int_div((status)->size, $sef$18); return 0; } int sizeofDatatype(MPI_Datatype datatype) { size_t result; switch (datatype) { case MPI_INT: result = sizeof(int); break; case MPI_2INT: result = sizeof(int) * 2; break; case MPI_FLOAT: result = sizeof(float); break; case MPI_DOUBLE: result = sizeof(double); break; case MPI_CHAR: result = sizeof(char); break; case MPI_BYTE: result = sizeof(char); break; case MPI_SHORT: result = sizeof(short); break; case MPI_LONG: result = sizeof(long); break; case MPI_LONG_DOUBLE: result = sizeof(long double); break; case MPI_LONG_LONG_INT: result = sizeof(long long); break; case MPI_LONG_LONG: result = sizeof(long long); break; case MPI_UNSIGNED_LONG_LONG: result = sizeof(unsigned long long); break; default: $assert(0, "Unreachable"); } return result; } MPI_Comm $mpi_comm_create($scope scope, $mpi_gcomm gc, int rank) { MPI_Comm result; result.p2p = $comm_create(scope, gc.p2p, rank); result.col = $comm_create(scope, gc.col, rank); result.collator = $collator_create(gc.gcollator, scope, rank); result.barrier = $barrier_create(scope, gc.gbarrier, rank); result.gcommIndex = 0; return result; } void $mpi_comm_destroy(MPI_Comm comm, $mpi_state mpi_state) { if (comm.gcommIndex == 0) $assert(mpi_state == _MPI_FINALIZED, "Process terminates without calling MPI_Finalize() first."); $comm_destroy(comm.p2p); $comm_destroy(comm.col); $free(comm.collator); $barrier_destroy(comm.barrier); } int $mpi_send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) { if ((dest >= 0) && (count >= 0)) { int $sef$26 = sizeofDatatype(datatype); int size = count * $sef$26; int place = $comm_place(comm.p2p); $message out; $elaborate(dest); out = $message_pack(place, dest, tag, buf, size); $comm_enqueue(comm.p2p, out); } return 0; } int $mpi_recv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status* status) { if (((source >= 0) || (source == (-1))) && (count >= 0)) { $message in; int place = $comm_place(comm.p2p); int deterministicTag; $assert((tag == (-2)) || (tag >= 0), "Illegal MPI message receive tag %d.\n", tag); deterministicTag = tag < 0 ? -2 : tag; $elaborate(source); in = $comm_dequeue(comm.p2p, source, deterministicTag); int $sef$27 = sizeofDatatype(datatype); int size = count * $sef$27; $message_unpack(in, buf, size); if (status != (void*)0) { (status)->size = $message_size(in); (status)->MPI_SOURCE = $message_source(in); (status)->MPI_TAG = $message_tag(in); (status)->MPI_ERROR = 0; } } return 0; } { _civl_main(_civl_argc, ((char*[_civl_argc]) $lambda (int i) _civl_argv[i])); } $mpi_comm_destroy(MPI_COMM_WORLD, _mpi_state); } int main() { _mpi_gcomm = $mpi_gcomm_create(_mpi_root, _mpi_nprocs); $seq_init(&(_mpi_gcomms), 1, &(_mpi_gcomm)); $parfor (int i: 0 .. _mpi_nprocs - 1) _mpi_process(i); $mpi_gcomm_destroy(_mpi_gcomm); }