#Enum optimization

1 messages · Page 1 of 1 (latest)

errant timber
#

Let's say there's an enum like this:

const Block = enum {
  a, b, c, d,

  fn model(self: @This()) Model {
    return switch (self) {
      b, c, d => .cube,
      else => .none,
    };
  }

  fn isFullbright(self: @This()) bool {
    return switch (self) {
      d => true,
      else => false,
    };
  }
};

Is it a good idea to make generic functions with switch statements like this? What I wonder is if the compiler is smart enough to optimize the many enum checks. Else I would have to write functions which contain only a single switch, but that doesn't feel nice.

fn generateMesh() void {
  // foreach block in volume
  const model = block.model();
  const is_fullbright = block.isFullbright();
}

Or like this if it can't optimize it.

fn generateMesh() void {
  // foreach block in volume
  const model, const is_fullbright = expr: switch (block) {
    a => break :expr .{.none, false},
    b, c => break :expr .{.cube, false},
    d => break :expr .{.cube, true},
  }
}
#

Or, would it perhaps be better to make an array with all the properties for the enums.

const PROPERTIES: []const Property = &.{
  .{.model = .none, .is_fullbright = false}, // a
  .{.model = .cube, .is_fullbright = false}, // b 
  .{.model = .cube, .is_fullbright = false}, // c
  .{.model = .cube, .is_fullbright = true}, // d
};

// Then
const model = Block.PROPERTIES[@intFromEnum(block)].model;
#

Enum optimization

foggy imp
errant timber
#

They all have different instructions

#

But what I would really like is a benchmark

hollow bison
#

because:

  1. it's a lot less readable
  2. it packs unrelated data next to each other, which is bad for cache locality, and
  3. the compiler will optimise switches to jump tables where it makes sense anyway
gilded tusk
#

looking at godbolt, zig is really not giving llvm good ir to work it. The porperties lookup table has the best codegen if you s/Property/Mesh:

export fn accessWithTable(block: Block) Mesh {
    return Block.PROPERTIES[@intFromEnum(block)];
}
errant timber
#

Well, in the examples I simplified it a lot, normally the mesh would be something like an array being appended with vertices.