aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig28
-rw-r--r--src/codegen/llvm.zig84
-rw-r--r--src/codegen/llvm/bindings.zig29
3 files changed, 131 insertions, 10 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 466322c0a3..ad98dc87c1 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -989,6 +989,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.mul_sat => try airSatOp(f, inst, "muls_"),
.shl_sat => try airSatOp(f, inst, "shls_"),
+ .min => try airMinMax(f, inst, "<"),
+ .max => try airMinMax(f, inst, ">"),
+
.cmp_eq => try airBinOp(f, inst, " == "),
.cmp_gt => try airBinOp(f, inst, " > "),
.cmp_gte => try airBinOp(f, inst, " >= "),
@@ -1595,6 +1598,31 @@ fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue
return local;
}
+fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
+ if (f.liveness.isUnused(inst)) return CValue.none;
+
+ const bin_op = f.air.instructions.items(.data)[inst].bin_op;
+ const lhs = try f.resolveInst(bin_op.lhs);
+ const rhs = try f.resolveInst(bin_op.rhs);
+
+ const writer = f.object.writer();
+ const inst_ty = f.air.typeOfIndex(inst);
+ const local = try f.allocLocal(inst_ty, .Const);
+
+ // (lhs <> rhs) ? lhs : rhs
+ try writer.writeAll(" = (");
+ try f.writeCValue(writer, lhs);
+ try writer.print("{s}", .{operator});
+ try f.writeCValue(writer, rhs);
+ try writer.writeAll(") ");
+ try f.writeCValue(writer, lhs);
+ try writer.writeAll(" : ");
+ try f.writeCValue(writer, rhs);
+ try writer.writeAll(";\n");
+
+ return local;
+}
+
fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const extra = f.air.extraData(Air.Call, pl_op.payload);
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index d5b8ee851a..1ebca942d5 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -754,7 +754,7 @@ pub const DeclGen = struct {
const fields: [2]*const llvm.Type = .{
try dg.llvmType(ptr_type),
- try dg.llvmType(Type.initTag(.usize)),
+ try dg.llvmType(Type.usize),
};
return dg.context.structType(&fields, fields.len, .False);
} else {
@@ -780,10 +780,14 @@ pub const DeclGen = struct {
return llvm_struct_ty;
},
.Array => {
- const elem_type = try dg.llvmType(t.elemType());
+ const elem_type = try dg.llvmType(t.childType());
const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null);
return elem_type.arrayType(@intCast(c_uint, total_len));
},
+ .Vector => {
+ const elem_type = try dg.llvmType(t.childType());
+ return elem_type.vectorType(@intCast(c_uint, t.arrayLen()));
+ },
.Optional => {
var buf: Type.Payload.ElemType = undefined;
const child_type = t.optionalChild(&buf);
@@ -966,7 +970,6 @@ pub const DeclGen = struct {
.Frame,
.AnyFrame,
- .Vector,
=> return dg.todo("implement llvmType for type '{}'", .{t}),
}
}
@@ -1062,7 +1065,7 @@ pub const DeclGen = struct {
return self.context.constStruct(&fields, fields.len, .False);
},
.int_u64 => {
- const llvm_usize = try self.llvmType(Type.initTag(.usize));
+ const llvm_usize = try self.llvmType(Type.usize);
const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False);
return llvm_int.constIntToPtr(try self.llvmType(tv.ty));
},
@@ -1295,7 +1298,7 @@ pub const DeclGen = struct {
.val = tv.val,
}),
try self.genTypedValue(.{
- .ty = Type.initTag(.usize),
+ .ty = Type.usize,
.val = Value.initPayload(&slice_len.base),
}),
};
@@ -1470,6 +1473,8 @@ pub const FuncGen = struct {
.shl => try self.airShl(inst),
.shl_sat => try self.airShlSat(inst),
.shl_exact => try self.airShlExact(inst),
+ .min => try self.airMin(inst),
+ .max => try self.airMax(inst),
.bit_and, .bool_and => try self.airAnd(inst),
.bit_or, .bool_or => try self.airOr(inst),
@@ -2356,6 +2361,32 @@ pub const FuncGen = struct {
return self.todo("implement llvm codegen for 'airWrapErrUnionErr'", .{});
}
+ fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ 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 scalar_ty = self.air.typeOfIndex(inst).scalarType();
+
+ if (scalar_ty.isAnyFloat()) return self.builder.buildMinNum(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildSMin(lhs, rhs, "");
+ return self.builder.buildUMin(lhs, rhs, "");
+ }
+
+ fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ 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 scalar_ty = self.air.typeOfIndex(inst).scalarType();
+
+ if (scalar_ty.isAnyFloat()) return self.builder.buildMaxNum(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildSMax(lhs, rhs, "");
+ return self.builder.buildUMax(lhs, rhs, "");
+ }
+
fn airAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null;
@@ -2705,15 +2736,48 @@ pub const FuncGen = struct {
}
fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
+ if (self.liveness.isUnused(inst)) return null;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
+ const operand_ty = self.air.typeOf(ty_op.operand);
const inst_ty = self.air.typeOfIndex(inst);
- const dest_type = try self.dg.llvmType(inst_ty);
+ const llvm_dest_ty = try self.dg.llvmType(inst_ty);
+
+ // TODO look into pulling this logic out into a different AIR instruction than bitcast
+ if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) {
+ const target = self.dg.module.getTarget();
+ const elem_ty = operand_ty.childType();
+ if (!isByRef(inst_ty)) {
+ return self.dg.todo("implement bitcast vector to non-ref array", .{});
+ }
+ const array_ptr = self.buildAlloca(llvm_dest_ty);
+ const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
+ if (bitcast_ok) {
+ const llvm_vector_ty = try self.dg.llvmType(operand_ty);
+ const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");
+ _ = self.builder.buildStore(operand, casted_ptr);
+ } else {
+ // If the ABI size of the element type is not evenly divisible by size in bits;
+ // a simple bitcast will not work, and we fall back to extractelement.
+ const llvm_usize = try self.dg.llvmType(Type.usize);
+ const llvm_u32 = self.context.intType(32);
+ const zero = llvm_usize.constNull();
+ const vector_len = operand_ty.arrayLen();
+ var i: u64 = 0;
+ while (i < vector_len) : (i += 1) {
+ const index_usize = llvm_usize.constInt(i, .False);
+ const index_u32 = llvm_u32.constInt(i, .False);
+ const indexes: [2]*const llvm.Value = .{ zero, index_usize };
+ const elem_ptr = self.builder.buildInBoundsGEP(array_ptr, &indexes, indexes.len, "");
+ const elem = self.builder.buildExtractElement(operand, index_u32, "");
+ _ = self.builder.buildStore(elem, elem_ptr);
+ }
+ }
+ return array_ptr;
+ }
- return self.builder.buildBitCast(operand, dest_type, "");
+ return self.builder.buildBitCast(operand, llvm_dest_ty, "");
}
fn airBoolToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
@@ -2906,7 +2970,7 @@ pub const FuncGen = struct {
}
// It's a pointer but we need to treat it as an int.
- const usize_llvm_ty = try self.dg.llvmType(Type.initTag(.usize));
+ const usize_llvm_ty = try self.dg.llvmType(Type.usize);
const casted_ptr = self.builder.buildBitCast(ptr, usize_llvm_ty.pointerType(0), "");
const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");
const uncasted_result = self.builder.buildAtomicRmw(
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
index 7b91d70fbe..5b6824f02a 100644
--- a/src/codegen/llvm/bindings.zig
+++ b/src/codegen/llvm/bindings.zig
@@ -212,6 +212,9 @@ pub const Type = opaque {
pub const arrayType = LLVMArrayType;
extern fn LLVMArrayType(ElementType: *const Type, ElementCount: c_uint) *const Type;
+ pub const vectorType = LLVMVectorType;
+ extern fn LLVMVectorType(ElementType: *const Type, ElementCount: c_uint) *const Type;
+
pub const structSetBody = LLVMStructSetBody;
extern fn LLVMStructSetBody(
StructTy: *const Type,
@@ -553,6 +556,14 @@ pub const Builder = opaque {
Name: [*:0]const u8,
) *const Value;
+ pub const buildExtractElement = LLVMBuildExtractElement;
+ extern fn LLVMBuildExtractElement(
+ *const Builder,
+ VecVal: *const Value,
+ Index: *const Value,
+ Name: [*:0]const u8,
+ ) *const Value;
+
pub const buildPtrToInt = LLVMBuildPtrToInt;
extern fn LLVMBuildPtrToInt(
*const Builder,
@@ -700,6 +711,24 @@ pub const Builder = opaque {
Size: *const Value,
is_volatile: bool,
) *const Value;
+
+ pub const buildMaxNum = ZigLLVMBuildMaxNum;
+ extern fn ZigLLVMBuildMaxNum(builder: *const Builder, LHS: *const Value, RHS: *const Value, name: [*:0]const u8) *const Value;
+
+ pub const buildMinNum = ZigLLVMBuildMinNum;
+ extern fn ZigLLVMBuildMinNum(builder: *const Builder, LHS: *const Value, RHS: *const Value, name: [*:0]const u8) *const Value;
+
+ pub const buildUMax = ZigLLVMBuildUMax;
+ extern fn ZigLLVMBuildUMax(builder: *const Builder, LHS: *const Value, RHS: *const Value, name: [*:0]const u8) *const Value;
+
+ pub const buildUMin = ZigLLVMBuildUMin;
+ extern fn ZigLLVMBuildUMin(builder: *const Builder, LHS: *const Value, RHS: *const Value, name: [*:0]const u8) *const Value;
+
+ pub const buildSMax = ZigLLVMBuildSMax;
+ extern fn ZigLLVMBuildSMax(builder: *const Builder, LHS: *const Value, RHS: *const Value, name: [*:0]const u8) *const Value;
+
+ pub const buildSMin = ZigLLVMBuildSMin;
+ extern fn ZigLLVMBuildSMin(builder: *const Builder, LHS: *const Value, RHS: *const Value, name: [*:0]const u8) *const Value;
};
pub const IntPredicate = enum(c_uint) {