Skip to content

Commit b58d8aa

Browse files
committed
stage2: improve LLVM backend for enums
* support lowering enum types and constants to LLVM IR * fix cmp instruction to support enum operands
1 parent 091a98f commit b58d8aa

File tree

3 files changed

+59
-32
lines changed

3 files changed

+59
-32
lines changed

src/codegen/llvm.zig

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,12 @@ pub const DeclGen = struct {
588588
const info = t.intInfo(self.module.getTarget());
589589
return self.context.intType(info.bits);
590590
},
591+
.Enum => {
592+
var buffer: Type.Payload.Bits = undefined;
593+
const int_ty = t.enumTagType(&buffer);
594+
const bit_count = int_ty.intInfo(self.module.getTarget()).bits;
595+
return self.context.intType(bit_count);
596+
},
591597
.Float => switch (t.floatBits(self.module.getTarget())) {
592598
16 => return self.context.halfType(),
593599
32 => return self.context.floatType(),
@@ -686,7 +692,6 @@ pub const DeclGen = struct {
686692

687693
.BoundFn => @panic("TODO remove BoundFn from the language"),
688694

689-
.Enum,
690695
.Union,
691696
.Opaque,
692697
.Frame,
@@ -723,6 +728,17 @@ pub const DeclGen = struct {
723728
}
724729
return llvm_int;
725730
},
731+
.Enum => {
732+
const llvm_type = try self.llvmType(tv.ty);
733+
const uint: u64 = uint: {
734+
if (tv.val.castTag(.enum_field_index)) |payload| {
735+
break :uint payload.data;
736+
}
737+
break :uint tv.val.toUnsignedInt();
738+
};
739+
const llvm_int = llvm_type.constInt(uint, .False);
740+
return llvm_int;
741+
},
726742
.Float => {
727743
if (tv.ty.floatBits(self.module.getTarget()) <= 64) {
728744
const llvm_ty = try self.llvmType(tv.ty);
@@ -907,7 +923,18 @@ pub const DeclGen = struct {
907923
.ComptimeFloat => unreachable,
908924
.Type => unreachable,
909925
.EnumLiteral => unreachable,
910-
else => return self.todo("implement const of type '{}'", .{tv.ty}),
926+
.Void => unreachable,
927+
.NoReturn => unreachable,
928+
.Undefined => unreachable,
929+
.Null => unreachable,
930+
.BoundFn => unreachable,
931+
.Opaque => unreachable,
932+
933+
.Union,
934+
.Frame,
935+
.AnyFrame,
936+
.Vector,
937+
=> return self.todo("implement const of type '{}'", .{tv.ty}),
911938
}
912939
}
913940

@@ -1195,21 +1222,15 @@ pub const FuncGen = struct {
11951222
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
11961223
const lhs = try self.resolveInst(bin_op.lhs);
11971224
const rhs = try self.resolveInst(bin_op.rhs);
1198-
const inst_ty = self.air.typeOfIndex(inst);
1225+
const operand_ty = self.air.typeOf(bin_op.lhs);
11991226

1200-
switch (self.air.typeOf(bin_op.lhs).zigTypeTag()) {
1201-
.Int, .Bool, .Pointer, .ErrorSet => {
1202-
const is_signed = inst_ty.isSignedInt();
1203-
const operation = switch (op) {
1204-
.eq => .EQ,
1205-
.neq => .NE,
1206-
.lt => @as(llvm.IntPredicate, if (is_signed) .SLT else .ULT),
1207-
.lte => @as(llvm.IntPredicate, if (is_signed) .SLE else .ULE),
1208-
.gt => @as(llvm.IntPredicate, if (is_signed) .SGT else .UGT),
1209-
.gte => @as(llvm.IntPredicate, if (is_signed) .SGE else .UGE),
1210-
};
1211-
return self.builder.buildICmp(operation, lhs, rhs, "");
1227+
const int_ty = switch (operand_ty.zigTypeTag()) {
1228+
.Enum => blk: {
1229+
var buffer: Type.Payload.Bits = undefined;
1230+
const int_ty = operand_ty.enumTagType(&buffer);
1231+
break :blk int_ty;
12121232
},
1233+
.Int, .Bool, .Pointer, .ErrorSet => operand_ty,
12131234
.Float => {
12141235
const operation: llvm.RealPredicate = switch (op) {
12151236
.eq => .OEQ,
@@ -1222,7 +1243,17 @@ pub const FuncGen = struct {
12221243
return self.builder.buildFCmp(operation, lhs, rhs, "");
12231244
},
12241245
else => unreachable,
1225-
}
1246+
};
1247+
const is_signed = int_ty.isSignedInt();
1248+
const operation = switch (op) {
1249+
.eq => .EQ,
1250+
.neq => .NE,
1251+
.lt => @as(llvm.IntPredicate, if (is_signed) .SLT else .ULT),
1252+
.lte => @as(llvm.IntPredicate, if (is_signed) .SLE else .ULE),
1253+
.gt => @as(llvm.IntPredicate, if (is_signed) .SGT else .UGT),
1254+
.gte => @as(llvm.IntPredicate, if (is_signed) .SGE else .UGE),
1255+
};
1256+
return self.builder.buildICmp(operation, lhs, rhs, "");
12261257
}
12271258

12281259
fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {

test/behavior/atomics.zig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,15 @@ test "cmpxchg on a global variable" {
118118
_ = @cmpxchgWeak(u32, &a_global_variable, 1234, 42, .Acquire, .Monotonic);
119119
try expect(a_global_variable == 42);
120120
}
121+
122+
test "atomic load and rmw with enum" {
123+
const Value = enum(u8) { a, b, c };
124+
var x = Value.a;
125+
126+
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
127+
128+
_ = @atomicRmw(Value, &x, .Xchg, .c, .SeqCst);
129+
try expect(@atomicLoad(Value, &x, .SeqCst) == .c);
130+
try expect(@atomicLoad(Value, &x, .SeqCst) != .a);
131+
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
132+
}

test/behavior/atomics_stage1.zig

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,6 @@ const expect = std.testing.expect;
33
const expectEqual = std.testing.expectEqual;
44
const builtin = @import("builtin");
55

6-
test "atomic load and rmw with enum" {
7-
const Value = enum(u8) {
8-
a,
9-
b,
10-
c,
11-
};
12-
var x = Value.a;
13-
14-
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
15-
16-
_ = @atomicRmw(Value, &x, .Xchg, .c, .SeqCst);
17-
try expect(@atomicLoad(Value, &x, .SeqCst) == .c);
18-
try expect(@atomicLoad(Value, &x, .SeqCst) != .a);
19-
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
20-
}
21-
226
test "atomic store" {
237
var x: u32 = 0;
248
@atomicStore(u32, &x, 1, .SeqCst);

0 commit comments

Comments
 (0)