diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 28 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 84 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 29 |
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) { |
