Skip to content

Commit 1a291c3

Browse files
committed
Point: apply hoist/restrict optimizations
1 parent 6e7e536 commit 1a291c3

1 file changed

Lines changed: 85 additions & 44 deletions

File tree

src/libImaging/Point.c

Lines changed: 85 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,39 @@ typedef struct {
2525
const void *table;
2626
} im_point_context;
2727

28+
/**
29+
* Contract: imIn is read-only and imOut must be a distinct image.
30+
*/
2831
static void
2932
im_point_8_8(Imaging imOut, Imaging imIn, im_point_context *context) {
30-
int x, y;
3133
/* 8-bit source, 8-bit destination */
3234
UINT8 *table = (UINT8 *)context->table;
33-
for (y = 0; y < imIn->ysize; y++) {
34-
UINT8 *in = imIn->image8[y];
35-
UINT8 *out = imOut->image8[y];
36-
for (x = 0; x < imIn->xsize; x++) {
35+
// Invariant over the loop.
36+
int xsize = imIn->xsize, ysize = imIn->ysize;
37+
for (int y = 0; y < ysize; y++) {
38+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
39+
UINT8 *restrict in = imIn->image8[y];
40+
UINT8 *restrict out = imOut->image8[y];
41+
for (int x = 0; x < xsize; x++) {
3742
out[x] = table[in[x]];
3843
}
3944
}
4045
}
4146

47+
/**
48+
* Contract: imIn is read-only and imOut must be a distinct image.
49+
*/
4250
static void
4351
im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context *context) {
44-
int x, y;
4552
/* 2x8-bit source, 2x8-bit destination */
4653
UINT8 *table = (UINT8 *)context->table;
47-
for (y = 0; y < imIn->ysize; y++) {
48-
UINT8 *in = (UINT8 *)imIn->image[y];
49-
UINT8 *out = (UINT8 *)imOut->image[y];
50-
for (x = 0; x < imIn->xsize; x++) {
54+
// Invariant over the loop.
55+
int xsize = imIn->xsize, ysize = imIn->ysize;
56+
for (int y = 0; y < ysize; y++) {
57+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
58+
UINT8 *restrict in = (UINT8 *)imIn->image[y];
59+
UINT8 *restrict out = (UINT8 *)imOut->image[y];
60+
for (int x = 0; x < xsize; x++) {
5161
out[0] = table[in[0]];
5262
out[3] = table[in[3] + 256];
5363
in += 4;
@@ -56,15 +66,20 @@ im_point_2x8_2x8(Imaging imOut, Imaging imIn, im_point_context *context) {
5666
}
5767
}
5868

69+
/**
70+
* Contract: imIn is read-only and imOut must be a distinct image.
71+
*/
5972
static void
6073
im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context *context) {
61-
int x, y;
6274
/* 3x8-bit source, 3x8-bit destination */
6375
UINT8 *table = (UINT8 *)context->table;
64-
for (y = 0; y < imIn->ysize; y++) {
65-
UINT8 *in = (UINT8 *)imIn->image[y];
66-
UINT8 *out = (UINT8 *)imOut->image[y];
67-
for (x = 0; x < imIn->xsize; x++) {
76+
// Invariant over the loop.
77+
int xsize = imIn->xsize, ysize = imIn->ysize;
78+
for (int y = 0; y < ysize; y++) {
79+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
80+
UINT8 *restrict in = (UINT8 *)imIn->image[y];
81+
UINT8 *restrict out = (UINT8 *)imOut->image[y];
82+
for (int x = 0; x < xsize; x++) {
6883
out[0] = table[in[0]];
6984
out[1] = table[in[1] + 256];
7085
out[2] = table[in[2] + 512];
@@ -74,15 +89,20 @@ im_point_3x8_3x8(Imaging imOut, Imaging imIn, im_point_context *context) {
7489
}
7590
}
7691

92+
/**
93+
* Contract: imIn is read-only and imOut must be a distinct image.
94+
*/
7795
static void
7896
im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context *context) {
79-
int x, y;
8097
/* 4x8-bit source, 4x8-bit destination */
8198
UINT8 *table = (UINT8 *)context->table;
82-
for (y = 0; y < imIn->ysize; y++) {
83-
UINT8 *in = (UINT8 *)imIn->image[y];
84-
UINT8 *out = (UINT8 *)imOut->image[y];
85-
for (x = 0; x < imIn->xsize; x++) {
99+
// Invariant over the loop.
100+
int xsize = imIn->xsize, ysize = imIn->ysize;
101+
for (int y = 0; y < ysize; y++) {
102+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
103+
UINT8 *restrict in = (UINT8 *)imIn->image[y];
104+
UINT8 *restrict out = (UINT8 *)imOut->image[y];
105+
for (int x = 0; x < xsize; x++) {
86106
out[0] = table[in[0]];
87107
out[1] = table[in[1] + 256];
88108
out[2] = table[in[2] + 512];
@@ -93,29 +113,39 @@ im_point_4x8_4x8(Imaging imOut, Imaging imIn, im_point_context *context) {
93113
}
94114
}
95115

116+
/**
117+
* Contract: imIn is read-only and imOut must be a distinct image.
118+
*/
96119
static void
97120
im_point_8_32(Imaging imOut, Imaging imIn, im_point_context *context) {
98-
int x, y;
99121
/* 8-bit source, 32-bit destination */
100122
char *table = (char *)context->table;
101-
for (y = 0; y < imIn->ysize; y++) {
102-
UINT8 *in = imIn->image8[y];
103-
INT32 *out = imOut->image32[y];
104-
for (x = 0; x < imIn->xsize; x++) {
123+
// Invariant over the loop.
124+
int xsize = imIn->xsize, ysize = imIn->ysize;
125+
for (int y = 0; y < ysize; y++) {
126+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
127+
UINT8 *restrict in = imIn->image8[y];
128+
INT32 *restrict out = imOut->image32[y];
129+
for (int x = 0; x < xsize; x++) {
105130
memcpy(out + x, table + in[x] * sizeof(INT32), sizeof(INT32));
106131
}
107132
}
108133
}
109134

135+
/**
136+
* Contract: imIn is read-only and imOut must be a distinct image.
137+
*/
110138
static void
111139
im_point_32_8(Imaging imOut, Imaging imIn, im_point_context *context) {
112-
int x, y;
113140
/* 32-bit source, 8-bit destination */
114141
UINT8 *table = (UINT8 *)context->table;
115-
for (y = 0; y < imIn->ysize; y++) {
116-
INT32 *in = imIn->image32[y];
117-
UINT8 *out = imOut->image8[y];
118-
for (x = 0; x < imIn->xsize; x++) {
142+
// Invariant over the loop.
143+
int xsize = imIn->xsize, ysize = imIn->ysize;
144+
for (int y = 0; y < ysize; y++) {
145+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
146+
INT32 *restrict in = imIn->image32[y];
147+
UINT8 *restrict out = imOut->image8[y];
148+
for (int x = 0; x < xsize; x++) {
119149
int v = in[x];
120150
if (v < 0) {
121151
v = 0;
@@ -202,43 +232,53 @@ ImagingPoint(Imaging imIn, ModeID mode, const void *table) {
202232
);
203233
}
204234

235+
/**
236+
* Apply an affine (scale/offset) transform to every pixel of imIn,
237+
* returning a newly allocated result.
238+
*
239+
* Contract: imIn is read-only.
240+
*/
205241
Imaging
206242
ImagingPointTransform(Imaging imIn, double scale, double offset) {
207243
/* scale/offset transform */
208244

209245
ImagingSectionCookie cookie;
210246
Imaging imOut;
211-
int x, y;
212247

213248
if (!imIn || (imIn->mode != IMAGING_MODE_I && imIn->mode != IMAGING_MODE_I_16 &&
214249
imIn->mode != IMAGING_MODE_F)) {
215250
return (Imaging)ImagingError_ModeError();
216251
}
217252

218-
imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize);
253+
// Invariant over the loops.
254+
int xsize = imIn->xsize, ysize = imIn->ysize;
255+
256+
imOut = ImagingNew(imIn->mode, xsize, ysize);
219257
if (!imOut) {
220258
return NULL;
221259
}
222260

223261
switch (imIn->type) {
224262
case IMAGING_TYPE_INT32:
225263
ImagingSectionEnter(&cookie);
226-
for (y = 0; y < imIn->ysize; y++) {
227-
INT32 *in = imIn->image32[y];
228-
INT32 *out = imOut->image32[y];
264+
for (int y = 0; y < ysize; y++) {
265+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
266+
INT32 *restrict in = imIn->image32[y];
267+
INT32 *restrict out = imOut->image32[y];
229268
/* FIXME: add clipping? */
230-
for (x = 0; x < imIn->xsize; x++) {
269+
for (int x = 0; x < xsize; x++) {
231270
out[x] = in[x] * scale + offset;
232271
}
233272
}
234273
ImagingSectionLeave(&cookie);
235274
break;
236275
case IMAGING_TYPE_FLOAT32:
237276
ImagingSectionEnter(&cookie);
238-
for (y = 0; y < imIn->ysize; y++) {
239-
FLOAT32 *in = (FLOAT32 *)imIn->image32[y];
240-
FLOAT32 *out = (FLOAT32 *)imOut->image32[y];
241-
for (x = 0; x < imIn->xsize; x++) {
277+
for (int y = 0; y < ysize; y++) {
278+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
279+
FLOAT32 *restrict in = (FLOAT32 *)imIn->image32[y];
280+
FLOAT32 *restrict out = (FLOAT32 *)imOut->image32[y];
281+
for (int x = 0; x < xsize; x++) {
242282
out[x] = in[x] * scale + offset;
243283
}
244284
}
@@ -247,11 +287,12 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) {
247287
case IMAGING_TYPE_SPECIAL:
248288
if (imIn->mode == IMAGING_MODE_I_16) {
249289
ImagingSectionEnter(&cookie);
250-
for (y = 0; y < imIn->ysize; y++) {
251-
char *in = (char *)imIn->image[y];
252-
char *out = (char *)imOut->image[y];
290+
for (int y = 0; y < ysize; y++) {
291+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
292+
char *restrict in = imIn->image[y];
293+
char *restrict out = imOut->image[y];
253294
/* FIXME: add clipping? */
254-
for (x = 0; x < imIn->xsize; x++) {
295+
for (int x = 0; x < xsize; x++) {
255296
UINT16 v;
256297
memcpy(&v, in + x * sizeof(v), sizeof(v));
257298
v = v * scale + offset;

0 commit comments

Comments
 (0)