mirror of
https://github.com/ziglang/zig.git
synced 2024-11-30 17:12:31 +00:00
stage2: improve LLVM backend for enums
* support lowering enum types and constants to LLVM IR * fix cmp instruction to support enum operands
This commit is contained in:
parent
091a98f524
commit
b58d8aa05f
@ -588,6 +588,12 @@ pub const DeclGen = struct {
|
||||
const info = t.intInfo(self.module.getTarget());
|
||||
return self.context.intType(info.bits);
|
||||
},
|
||||
.Enum => {
|
||||
var buffer: Type.Payload.Bits = undefined;
|
||||
const int_ty = t.enumTagType(&buffer);
|
||||
const bit_count = int_ty.intInfo(self.module.getTarget()).bits;
|
||||
return self.context.intType(bit_count);
|
||||
},
|
||||
.Float => switch (t.floatBits(self.module.getTarget())) {
|
||||
16 => return self.context.halfType(),
|
||||
32 => return self.context.floatType(),
|
||||
@ -686,7 +692,6 @@ pub const DeclGen = struct {
|
||||
|
||||
.BoundFn => @panic("TODO remove BoundFn from the language"),
|
||||
|
||||
.Enum,
|
||||
.Union,
|
||||
.Opaque,
|
||||
.Frame,
|
||||
@ -723,6 +728,17 @@ pub const DeclGen = struct {
|
||||
}
|
||||
return llvm_int;
|
||||
},
|
||||
.Enum => {
|
||||
const llvm_type = try self.llvmType(tv.ty);
|
||||
const uint: u64 = uint: {
|
||||
if (tv.val.castTag(.enum_field_index)) |payload| {
|
||||
break :uint payload.data;
|
||||
}
|
||||
break :uint tv.val.toUnsignedInt();
|
||||
};
|
||||
const llvm_int = llvm_type.constInt(uint, .False);
|
||||
return llvm_int;
|
||||
},
|
||||
.Float => {
|
||||
if (tv.ty.floatBits(self.module.getTarget()) <= 64) {
|
||||
const llvm_ty = try self.llvmType(tv.ty);
|
||||
@ -907,7 +923,18 @@ pub const DeclGen = struct {
|
||||
.ComptimeFloat => unreachable,
|
||||
.Type => unreachable,
|
||||
.EnumLiteral => unreachable,
|
||||
else => return self.todo("implement const of type '{}'", .{tv.ty}),
|
||||
.Void => unreachable,
|
||||
.NoReturn => unreachable,
|
||||
.Undefined => unreachable,
|
||||
.Null => unreachable,
|
||||
.BoundFn => unreachable,
|
||||
.Opaque => unreachable,
|
||||
|
||||
.Union,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
.Vector,
|
||||
=> return self.todo("implement const of type '{}'", .{tv.ty}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1195,21 +1222,15 @@ pub const FuncGen = struct {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
const inst_ty = self.air.typeOfIndex(inst);
|
||||
const operand_ty = self.air.typeOf(bin_op.lhs);
|
||||
|
||||
switch (self.air.typeOf(bin_op.lhs).zigTypeTag()) {
|
||||
.Int, .Bool, .Pointer, .ErrorSet => {
|
||||
const is_signed = inst_ty.isSignedInt();
|
||||
const operation = switch (op) {
|
||||
.eq => .EQ,
|
||||
.neq => .NE,
|
||||
.lt => @as(llvm.IntPredicate, if (is_signed) .SLT else .ULT),
|
||||
.lte => @as(llvm.IntPredicate, if (is_signed) .SLE else .ULE),
|
||||
.gt => @as(llvm.IntPredicate, if (is_signed) .SGT else .UGT),
|
||||
.gte => @as(llvm.IntPredicate, if (is_signed) .SGE else .UGE),
|
||||
};
|
||||
return self.builder.buildICmp(operation, lhs, rhs, "");
|
||||
const int_ty = switch (operand_ty.zigTypeTag()) {
|
||||
.Enum => blk: {
|
||||
var buffer: Type.Payload.Bits = undefined;
|
||||
const int_ty = operand_ty.enumTagType(&buffer);
|
||||
break :blk int_ty;
|
||||
},
|
||||
.Int, .Bool, .Pointer, .ErrorSet => operand_ty,
|
||||
.Float => {
|
||||
const operation: llvm.RealPredicate = switch (op) {
|
||||
.eq => .OEQ,
|
||||
@ -1222,7 +1243,17 @@ pub const FuncGen = struct {
|
||||
return self.builder.buildFCmp(operation, lhs, rhs, "");
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
const is_signed = int_ty.isSignedInt();
|
||||
const operation = switch (op) {
|
||||
.eq => .EQ,
|
||||
.neq => .NE,
|
||||
.lt => @as(llvm.IntPredicate, if (is_signed) .SLT else .ULT),
|
||||
.lte => @as(llvm.IntPredicate, if (is_signed) .SLE else .ULE),
|
||||
.gt => @as(llvm.IntPredicate, if (is_signed) .SGT else .UGT),
|
||||
.gte => @as(llvm.IntPredicate, if (is_signed) .SGE else .UGE),
|
||||
};
|
||||
return self.builder.buildICmp(operation, lhs, rhs, "");
|
||||
}
|
||||
|
||||
fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
|
@ -118,3 +118,15 @@ test "cmpxchg on a global variable" {
|
||||
_ = @cmpxchgWeak(u32, &a_global_variable, 1234, 42, .Acquire, .Monotonic);
|
||||
try expect(a_global_variable == 42);
|
||||
}
|
||||
|
||||
test "atomic load and rmw with enum" {
|
||||
const Value = enum(u8) { a, b, c };
|
||||
var x = Value.a;
|
||||
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
|
||||
|
||||
_ = @atomicRmw(Value, &x, .Xchg, .c, .SeqCst);
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) == .c);
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) != .a);
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
|
||||
}
|
||||
|
@ -3,22 +3,6 @@ const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
test "atomic load and rmw with enum" {
|
||||
const Value = enum(u8) {
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
};
|
||||
var x = Value.a;
|
||||
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
|
||||
|
||||
_ = @atomicRmw(Value, &x, .Xchg, .c, .SeqCst);
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) == .c);
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) != .a);
|
||||
try expect(@atomicLoad(Value, &x, .SeqCst) != .b);
|
||||
}
|
||||
|
||||
test "atomic store" {
|
||||
var x: u32 = 0;
|
||||
@atomicStore(u32, &x, 1, .SeqCst);
|
||||
|
Loading…
Reference in New Issue
Block a user