What's the point of writing "manual SIMD code"?

Er, x != x. I believe it should work.

assuming you mean movemask(x != x) == 0xF, since just using x != x gives you the familiar error about not able to convert to boolean, but I’m afraid that is also a no go.

same code works in float, but of dropping to float for any filter usage with this tight of a loop negates the use of simd.

My first guess works. movemask(x == x) != 0xf means “At least one element of x is NAN.” x == x itself returns a vector mask.

hm. movemask(x == x) != 0xf isn’t working for me. behavior is that NaN still passes through - same as when using float and not having the isnan() check.

editing to add:

the interesting thing is that when I add an fprintf inside the result of the if (movemask(x != x) == 0xF) then it correctly checks and enters that branch (the results of the if), but without the fprintf that branch is never executed.

I guess the compiler removes an empty branch. Try to disable the flags for optimization in compile.mk.

the rest of the branch isn’t empty:

if (movemask(x != x) == 0xF) {
  fprintf(stderr, "in branch\n");
  filter.reset();
}

Filter::reset() {
  foo = 0;
  bar = 0;
  fprintf(stderr, "in reset\n");
}

executes with output of:

in branch
in reset
if (movemask(x != x) == 0xF) {
  filter.reset();
}

Filter::reset() {
  foo = 0;
  bar = 0;
  fprintf(stderr, "in reset\n");
}

has no output whatsoever, and the filter itself isn’t reset - I’m very used to compilers removing empty branches, I’m not used to a branch not being empty and not being executed, so something else funky appears to be going on in this case.

Quick question: Is it ok to initialize to zero this way?

simd::float_4 out[4] = {};

Is it initialised?

simd::float_4 out[4] = {0.f};

Had an issue with poly channels before, using float[] where there was noise on the empty channels initialised with = {};

Yes, that initializes the array of vectors with zeroes, just like if you did float out[16] = {}.

In this case, = {0.f} is functionally equivalent to = {}.

Thanks!

Another question, not sure if I’m missing something. I’m trying to remove branching from my code:

int32_4 v = int32_4::load(...);
int32_4 mask = v == 0;

How can I use mask for ifelse(float_4 mask, float_4 a, float_4 b)?

Edit: It works this way but I’m not sure if it should be done this way?

int32_4 v = int32_4::load(...);
float_4 mask = float_4(v == 0) == -1.f;

There is no branching in that code.

Yeah, I posted the code that I’m working on. Before it was something like this with two branches inside the for-loop:

float_4 out[PORTS / 4];
...
for (int i = 0; i < PORTS; i++) {
	float v = outputMode[i] == OUTPUTMODE::OM_OUT ? out[i / 4][i % 4] : 0.f;
	if (outputClamp) v = clamp(v, -10.f, 10.f);
	outputs[OUTPUT + i].setVoltage(v);
}

This is how I did it using SIMD:

float_4 out[PORTS / 4];
...
simd::float_4 c = outputClamp;
for (int j = 0; j < PORTS; j+=4) {
	out[j / 4] = simd::ifelse(c == 1.f, simd::clamp(out[j / 4], -10.f, 10.f), out[j / 4]);
	simd::int32_4 o1 = simd::int32_4::load((int32_t*)&outputMode[j]);
	simd::float_4 o2 = simd::float_4(o1 != 0) == -1.f;
	out[j / 4] = simd::ifelse(o2, out[j / 4], simd::float_4::zero());
}
for (int i = 0; i < PORTS; i++) {
	outputs[OUTPUT + i].setVoltage(out[i / 4][i % 4]);
}