Commit 5ce0914f authored by Swann Perarnau's avatar Swann Perarnau

Merge branch 'padded-layouts' into 'master'

[feature] add padded layouts

See merge request !80
parents 12fee91a 73b7c567
Pipeline #8406 passed with stages
in 9 minutes and 54 seconds
/*******************************************************************************
* Copyright 2019 UChicago Argonne, LLC.
* (c.f. AUTHORS, LICENSE)
*
* This file is part of the AML project.
* For more info, see https://xgitlab.cels.anl.gov/argo/aml
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
#ifndef AML_LAYOUT_PAD_H
#define AML_LAYOUT_PAD_H 1
/**
* @defgroup aml_layout_pad "AML Layout Pad"
* @brief Padded layout.
*
* Padded layouts describe layouts that have been padded with neutral elements
* along one or several of their dimensions.
*
* #include <aml/layout/pad.h>
* @see aml_layout
* @{
**/
/**
* Structure of a padded layout.
**/
struct aml_layout_pad {
/** tags for this layout **/
int tags;
/** underlying layout which shape is being extended. **/
struct aml_layout *target;
/** number of dimensions: same of underlying layout **/
size_t ndims;
/** size of an element **/
size_t element_size;
/** dimensions of the padded layout **/
size_t *dims;
/** dimensions of the underlying layout **/
size_t *target_dims;
/** pointer to a neutral element to use for padding **/
void *neutral;
};
int aml_layout_pad_create(struct aml_layout **layout, const int order,
struct aml_layout *target, const size_t *dim,
void *neutral);
void aml_layout_pad_destroy(struct aml_layout **layout);
/**
* Pre-existing operators for padded layout
* with AML_LAYOUT_ORDER_COLUMN_MAJOR order.
**/
extern struct aml_layout_ops aml_layout_pad_column_ops;
/**
* Pre-existing operators for padded layout
* with AML_LAYOUT_ORDER_COLUMN_MAJOR order.
**/
extern struct aml_layout_ops aml_layout_pad_row_ops;
#endif
......@@ -51,7 +51,15 @@
**/
#define AML_INNER_MALLOC_EXTRA(a, b, c, sz) \
calloc(1, AML_SIZEOF_ALIGNED(struct { a __f1; b __f2; }, c) + \
(sizeof(c)*sz))
(sizeof(c)*(sz)))
/** Allocate a pointer that can be used to contain two types plus an extra area
* aligned on a third type, and extra bytes after that.
*
**/
#define AML_INNER_MALLOC_4(a, b, c, sz, d) \
calloc(1, AML_SIZEOF_ALIGNED(struct { a __f1; b __f2; }, c) + \
(sizeof(c)*(sz)) + d)
/** Returns the next pointer after an AML_INNER_MALLOC.
*
......
......@@ -13,6 +13,7 @@ AREA_SOURCES = \
LAYOUT_SOURCES = \
layout/layout.c \
layout/dense.c \
layout/pad.c \
layout/reshape.c
DMA_SOURCES = \
......
/*******************************************************************************
* Copyright 2019 UChicago Argonne, LLC.
* (c.f. AUTHORS, LICENSE)
*
* This file is part of the AML project.
* For more info, see https://xgitlab.cels.anl.gov/argo/aml
*
* SPDX-License-Identifier: BSD-3-Clause
******************************************************************************/
#include "aml.h"
#include "aml/layout/pad.h"
static int aml_layout_pad_alloc(struct aml_layout **ret,
const size_t ndims, size_t element_size)
{
struct aml_layout *layout;
struct aml_layout_pad *data;
layout = AML_INNER_MALLOC_4(struct aml_layout,
struct aml_layout_pad,
size_t, 2*ndims, element_size);
if (layout == NULL) {
*ret = NULL;
return -AML_ENOMEM;
}
data = AML_INNER_MALLOC_NEXTPTR(layout,
struct aml_layout,
struct aml_layout_pad);
layout->data = (struct aml_layout_data *) data;
data->dims = AML_INNER_MALLOC_EXTRA_NEXTPTR(layout,
struct aml_layout,
struct aml_layout_pad,
size_t, 0);
data->target_dims = AML_INNER_MALLOC_EXTRA_NEXTPTR(layout,
struct aml_layout,
struct aml_layout_pad,
size_t, ndims);
data->neutral = AML_INNER_MALLOC_EXTRA_NEXTPTR(layout,
struct aml_layout,
struct aml_layout_pad,
size_t, 2*ndims);
data->target = NULL;
data->ndims = ndims;
*ret = layout;
return AML_SUCCESS;
}
int aml_layout_pad_create(struct aml_layout **layout, const int order,
struct aml_layout *target, const size_t *dims,
void *neutral)
{
struct aml_layout *l;
struct aml_layout_pad *data;
int err, type;
size_t ndims, element_size;
if (layout == NULL || target == NULL || dims == NULL || neutral == NULL)
return -AML_EINVAL;
ndims = aml_layout_ndims(target);
element_size = aml_layout_element_size(target);
if (!ndims || !element_size)
return -AML_EINVAL;
err = aml_layout_pad_alloc(&l, ndims, element_size);
if (err)
return err;
data = (struct aml_layout_pad *)l->data;
data->target = target;
memcpy(data->neutral, neutral, element_size);
data->tags = order;
switch (AML_LAYOUT_ORDER(order)) {
case AML_LAYOUT_ORDER_ROW_MAJOR:
l->ops = &aml_layout_pad_row_ops;
for (size_t i = 0; i < ndims; i++)
data->dims[i] = dims[ndims-i-1];
break;
case AML_LAYOUT_ORDER_COLUMN_MAJOR:
l->ops = &aml_layout_pad_column_ops;
memcpy(data->dims, dims, ndims * sizeof(size_t));
break;
default:
free(l);
return -AML_EINVAL;
}
type = aml_layout_order(target);
if (AML_LAYOUT_ORDER(type) == AML_LAYOUT_ORDER_ROW_MAJOR) {
size_t target_dims[ndims];
aml_layout_dims(target, target_dims);
for (size_t i = 0; i < ndims; i++)
data->target_dims[i] = target_dims[ndims-i-1];
} else if (AML_LAYOUT_ORDER(type) == AML_LAYOUT_ORDER_COLUMN_MAJOR) {
aml_layout_dims(target, data->target_dims);
} else {
free(l);
return -AML_EINVAL;
}
*layout = l;
return AML_SUCCESS;
}
void aml_layout_pad_destroy(struct aml_layout **l)
{
if (l == NULL || *l == NULL)
return;
free(*l);
*l = NULL;
}
/*******************************************************************************
* COLUMN OPERATORS:
******************************************************************************/
void *aml_layout_pad_column_deref(const struct aml_layout_data *data,
const size_t *coords)
{
assert(data != NULL);
const struct aml_layout_pad *d = (const struct aml_layout_pad *)data;
size_t ndims = d->ndims;
for (size_t i = 0; i < ndims; i++) {
if (coords[i] >= d->target_dims[i])
return d->neutral;
}
return d->target->ops->deref_native(d->target->data, coords);
}
int aml_layout_pad_column_order(const struct aml_layout_data *data)
{
(void)data;
return AML_LAYOUT_ORDER_COLUMN_MAJOR;
}
int aml_layout_pad_column_dims(const struct aml_layout_data *data,
size_t *dims)
{
assert(data != NULL);
assert(dims != NULL);
const struct aml_layout_pad *d = (const struct aml_layout_pad *)data;
memcpy((void *)dims, (void *)d->dims, sizeof(size_t)*d->ndims);
return 0;
}
size_t aml_layout_pad_ndims(const struct aml_layout_data *data)
{
const struct aml_layout_pad *d = (const struct aml_layout_pad *)data;
return d->ndims;
}
size_t aml_layout_pad_element_size(const struct aml_layout_data *data)
{
const struct aml_layout_pad *d = (const struct aml_layout_pad *)data;
return d->element_size;
}
struct aml_layout_ops aml_layout_pad_column_ops = {
aml_layout_pad_column_deref,
aml_layout_pad_column_deref,
aml_layout_pad_column_order,
aml_layout_pad_column_dims,
aml_layout_pad_column_dims,
aml_layout_pad_ndims,
aml_layout_pad_element_size,
NULL,
NULL,
NULL,
};
/*******************************************************************************
* ROW OPERATORS:
******************************************************************************/
void *aml_layout_pad_row_deref(const struct aml_layout_data *data,
const size_t *coords)
{
assert(data != NULL);
const struct aml_layout_pad *d = (const struct aml_layout_pad *)data;
size_t ndims = d->ndims;
int type;
for (size_t i = 0; i < ndims; i++) {
if (coords[ndims - i - 1] >= d->target_dims[i])
return d->neutral;
}
type = aml_layout_order(d->target);
if (AML_LAYOUT_ORDER(type) == AML_LAYOUT_ORDER_ROW_MAJOR) {
return aml_layout_deref(d->target, coords);
} else if (AML_LAYOUT_ORDER(type) == AML_LAYOUT_ORDER_COLUMN_MAJOR) {
size_t target_coords[ndims];
for (size_t i = 0; i < ndims; i++)
target_coords[i] = coords[ndims - i - 1];
return aml_layout_deref(d->target, target_coords);
} else
return NULL;
}
int aml_layout_pad_row_order(const struct aml_layout_data *data)
{
(void)data;
return AML_LAYOUT_ORDER_ROW_MAJOR;
}
int aml_layout_pad_row_dims(const struct aml_layout_data *data, size_t *dims)
{
assert(data != NULL);
const struct aml_layout_pad *d = (const struct aml_layout_pad *)data;
for (size_t i = 0; i < d->ndims; i++)
dims[i] = d->dims[d->ndims - i - 1];
return 0;
}
struct aml_layout_ops aml_layout_pad_row_ops = {
aml_layout_pad_row_deref,
aml_layout_pad_row_deref,
aml_layout_pad_row_order,
aml_layout_pad_row_dims,
aml_layout_pad_row_dims,
aml_layout_pad_ndims,
aml_layout_pad_element_size,
NULL,
NULL,
NULL,
};
......@@ -2,6 +2,7 @@
#include <aml/layout/dense.h>
#include <aml/layout/reshape.h>
#include <aml/layout/native.h>
#include <aml/layout/pad.h>
#include <assert.h>
void test_slice_contiguous(void)
......@@ -633,12 +634,37 @@ void test_base(void)
aml_layout_dense_destroy(&a);
}
void test_pad()
{
struct aml_layout *a, *b;
float memory[7][11];
size_t dims[2] = {7, 11};
size_t dims_pad[2] = {11, 13};
float one = 1.0;
size_t ret_dims[2];
assert(!aml_layout_dense_create(&a, (void *)memory, AML_LAYOUT_ORDER_C,
sizeof(float), 2, dims, NULL, NULL));
assert(!aml_layout_pad_create(&b, AML_LAYOUT_ORDER_C, a,
dims_pad, &one));
assert(aml_layout_ndims(b) == 2);
assert(!aml_layout_dims(b, ret_dims));
assert(!memcmp(ret_dims, dims_pad, sizeof(size_t)*2));
ret_dims[0] = 10;
ret_dims[1] = 12;
assert(*(float *)aml_layout_deref(b, ret_dims) == one);
aml_layout_pad_destroy(&b);
aml_layout_dense_destroy(&a);
}
int main(int argc, char *argv[])
{
/* library initialization */
aml_init(&argc, &argv);
test_base();
test_pad();
test_reshape_contiguous();
test_reshape_discontiguous();
test_reshape_strided();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment