mirror of
https://github.com/ziglang/zig.git
synced 2024-12-24 12:10:16 +00:00
commit
6a5094872f
@ -94,6 +94,12 @@ pub const Inst = struct {
|
|||||||
/// Result type is the same as both operands.
|
/// Result type is the same as both operands.
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
bit_or,
|
bit_or,
|
||||||
|
/// Shift right. `>>`
|
||||||
|
/// Uses the `bin_op` field.
|
||||||
|
shr,
|
||||||
|
/// Shift left. `<<`
|
||||||
|
/// Uses the `bin_op` field.
|
||||||
|
shl,
|
||||||
/// Bitwise XOR. `^`
|
/// Bitwise XOR. `^`
|
||||||
/// Uses the `bin_op` field.
|
/// Uses the `bin_op` field.
|
||||||
xor,
|
xor,
|
||||||
@ -445,6 +451,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
|||||||
.xor,
|
.xor,
|
||||||
.ptr_add,
|
.ptr_add,
|
||||||
.ptr_sub,
|
.ptr_sub,
|
||||||
|
.shr,
|
||||||
|
.shl,
|
||||||
=> return air.typeOf(datas[inst].bin_op.lhs),
|
=> return air.typeOf(datas[inst].bin_op.lhs),
|
||||||
|
|
||||||
.cmp_lt,
|
.cmp_lt,
|
||||||
|
@ -249,6 +249,8 @@ fn analyzeInst(
|
|||||||
.ptr_slice_elem_val,
|
.ptr_slice_elem_val,
|
||||||
.ptr_elem_val,
|
.ptr_elem_val,
|
||||||
.ptr_ptr_elem_val,
|
.ptr_ptr_elem_val,
|
||||||
|
.shl,
|
||||||
|
.shr,
|
||||||
=> {
|
=> {
|
||||||
const o = inst_datas[inst].bin_op;
|
const o = inst_datas[inst].bin_op;
|
||||||
return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none });
|
return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none });
|
||||||
|
67
src/Sema.zig
67
src/Sema.zig
@ -5294,17 +5294,50 @@ fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
|
|||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
_ = block;
|
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||||
_ = inst;
|
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
|
||||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirShl", .{});
|
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
|
||||||
|
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
|
||||||
|
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||||
|
const lhs = sema.resolveInst(extra.lhs);
|
||||||
|
const rhs = sema.resolveInst(extra.rhs);
|
||||||
|
|
||||||
|
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
|
||||||
|
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
|
||||||
|
if (lhs_val.isUndef() or rhs_val.isUndef()) {
|
||||||
|
return sema.addConstUndef(sema.typeOf(lhs));
|
||||||
|
}
|
||||||
|
return sema.mod.fail(&block.base, src, "TODO implement comptime shl", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try sema.requireRuntimeBlock(block, src);
|
||||||
|
return block.addBinOp(.shl, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirShr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
_ = inst;
|
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{});
|
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
|
||||||
|
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
|
||||||
|
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
|
||||||
|
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||||
|
const lhs = sema.resolveInst(extra.lhs);
|
||||||
|
const rhs = sema.resolveInst(extra.rhs);
|
||||||
|
|
||||||
|
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
|
||||||
|
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
|
||||||
|
if (lhs_val.isUndef() or rhs_val.isUndef()) {
|
||||||
|
return sema.addConstUndef(sema.typeOf(lhs));
|
||||||
|
}
|
||||||
|
return sema.mod.fail(&block.base, src, "TODO implement comptime shr", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try sema.requireRuntimeBlock(block, src);
|
||||||
|
return block.addBinOp(.shr, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirBitwise(
|
fn zirBitwise(
|
||||||
@ -6001,13 +6034,33 @@ fn zirTypeofElem(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Compile
|
|||||||
fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirTypeofLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||||
const src = inst_data.src();
|
const src = inst_data.src();
|
||||||
return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeofLog2IntType", .{});
|
const operand = sema.resolveInst(inst_data.operand);
|
||||||
|
const operand_ty = sema.typeOf(operand);
|
||||||
|
return sema.log2IntType(block, operand_ty, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirLog2IntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||||
const src = inst_data.src();
|
const src = inst_data.src();
|
||||||
return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirLog2IntType", .{});
|
const operand = try sema.resolveType(block, src, inst_data.operand);
|
||||||
|
return sema.log2IntType(block, operand, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log2IntType(sema: *Sema, block: *Scope.Block, operand: Type, src: LazySrcLoc) CompileError!Air.Inst.Ref {
|
||||||
|
if (operand.zigTypeTag() != .Int) return sema.mod.fail(
|
||||||
|
&block.base,
|
||||||
|
src,
|
||||||
|
"bit shifting operation expected integer type, found '{}'",
|
||||||
|
.{operand},
|
||||||
|
);
|
||||||
|
|
||||||
|
var count: u16 = 0;
|
||||||
|
var s = operand.bitSize(sema.mod.getTarget()) - 1;
|
||||||
|
while (s != 0) : (s >>= 1) {
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
const res = try Module.makeIntType(sema.arena, .unsigned, count);
|
||||||
|
return sema.addType(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirTypeofPeer(
|
fn zirTypeofPeer(
|
||||||
|
@ -822,6 +822,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
.bit_and => try self.airBitAnd(inst),
|
.bit_and => try self.airBitAnd(inst),
|
||||||
.bit_or => try self.airBitOr(inst),
|
.bit_or => try self.airBitOr(inst),
|
||||||
.xor => try self.airXor(inst),
|
.xor => try self.airXor(inst),
|
||||||
|
.shr => try self.airShr(inst),
|
||||||
|
.shl => try self.airShl(inst),
|
||||||
|
|
||||||
.alloc => try self.airAlloc(inst),
|
.alloc => try self.airAlloc(inst),
|
||||||
.arg => try self.airArg(inst),
|
.arg => try self.airArg(inst),
|
||||||
@ -1272,6 +1274,24 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airShl(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||||
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||||
|
.arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shl),
|
||||||
|
else => return self.fail("TODO implement shl for {}", .{self.target.cpu.arch}),
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn airShr(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
|
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||||
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||||
|
.arm, .armeb => try self.genArmBinOp(inst, bin_op.lhs, bin_op.rhs, .shr),
|
||||||
|
else => return self.fail("TODO implement shr for {}", .{self.target.cpu.arch}),
|
||||||
|
};
|
||||||
|
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||||
|
}
|
||||||
|
|
||||||
fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
|
fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
|
||||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||||
|
@ -871,6 +871,9 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
|
|||||||
.bit_or => try airBinOp(o, inst, " | "),
|
.bit_or => try airBinOp(o, inst, " | "),
|
||||||
.xor => try airBinOp(o, inst, " ^ "),
|
.xor => try airBinOp(o, inst, " ^ "),
|
||||||
|
|
||||||
|
.shr => try airBinOp(o, inst, " >> "),
|
||||||
|
.shl => try airBinOp(o, inst, " << "),
|
||||||
|
|
||||||
.not => try airNot( o, inst),
|
.not => try airNot( o, inst),
|
||||||
|
|
||||||
.optional_payload => try airOptionalPayload(o, inst),
|
.optional_payload => try airOptionalPayload(o, inst),
|
||||||
|
@ -993,6 +993,9 @@ pub const FuncGen = struct {
|
|||||||
.bit_or, .bool_or => try self.airOr(inst),
|
.bit_or, .bool_or => try self.airOr(inst),
|
||||||
.xor => try self.airXor(inst),
|
.xor => try self.airXor(inst),
|
||||||
|
|
||||||
|
.shl => try self.airShl(inst),
|
||||||
|
.shr => try self.airShr(inst),
|
||||||
|
|
||||||
.cmp_eq => try self.airCmp(inst, .eq),
|
.cmp_eq => try self.airCmp(inst, .eq),
|
||||||
.cmp_gt => try self.airCmp(inst, .gt),
|
.cmp_gt => try self.airCmp(inst, .gt),
|
||||||
.cmp_gte => try self.airCmp(inst, .gte),
|
.cmp_gte => try self.airCmp(inst, .gte),
|
||||||
@ -1736,6 +1739,41 @@ pub const FuncGen = struct {
|
|||||||
return self.builder.buildXor(lhs, rhs, "");
|
return self.builder.buildXor(lhs, rhs, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn airShl(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 lhs_type = self.air.typeOf(bin_op.lhs);
|
||||||
|
const tg = self.dg.module.getTarget();
|
||||||
|
const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
|
||||||
|
self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
|
||||||
|
else
|
||||||
|
rhs;
|
||||||
|
return self.builder.buildShl(lhs, casted_rhs, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn airShr(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 lhs_type = self.air.typeOf(bin_op.lhs);
|
||||||
|
const tg = self.dg.module.getTarget();
|
||||||
|
const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
|
||||||
|
self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
|
||||||
|
else
|
||||||
|
rhs;
|
||||||
|
|
||||||
|
if (self.air.typeOfIndex(inst).isSignedInt()) {
|
||||||
|
return self.builder.buildAShr(lhs, casted_rhs, "");
|
||||||
|
} else {
|
||||||
|
return self.builder.buildLShr(lhs, casted_rhs, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||||
if (self.liveness.isUnused(inst))
|
if (self.liveness.isUnused(inst))
|
||||||
return null;
|
return null;
|
||||||
|
@ -290,6 +290,14 @@ pub const Builder = opaque {
|
|||||||
pub const getInsertBlock = LLVMGetInsertBlock;
|
pub const getInsertBlock = LLVMGetInsertBlock;
|
||||||
extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock;
|
extern fn LLVMGetInsertBlock(Builder: *const Builder) *const BasicBlock;
|
||||||
|
|
||||||
|
pub const buildZExt = LLVMBuildZExt;
|
||||||
|
extern fn LLVMBuildZExt(
|
||||||
|
*const Builder,
|
||||||
|
Value: *const Value,
|
||||||
|
DestTy: *const Type,
|
||||||
|
Name: [*:0]const u8,
|
||||||
|
) *const Value;
|
||||||
|
|
||||||
pub const buildCall = LLVMBuildCall;
|
pub const buildCall = LLVMBuildCall;
|
||||||
extern fn LLVMBuildCall(
|
extern fn LLVMBuildCall(
|
||||||
*const Builder,
|
*const Builder,
|
||||||
@ -381,6 +389,15 @@ pub const Builder = opaque {
|
|||||||
pub const buildAnd = LLVMBuildAnd;
|
pub const buildAnd = LLVMBuildAnd;
|
||||||
extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildAnd(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildLShr = LLVMBuildLShr;
|
||||||
|
extern fn LLVMBuildLShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildAShr = LLVMBuildAShr;
|
||||||
|
extern fn LLVMBuildAShr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
pub const buildShl = LLVMBuildShl;
|
||||||
|
extern fn LLVMBuildShl(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
pub const buildOr = LLVMBuildOr;
|
pub const buildOr = LLVMBuildOr;
|
||||||
extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
extern fn LLVMBuildOr(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
|
||||||
|
|
||||||
|
@ -127,6 +127,8 @@ const Writer = struct {
|
|||||||
.ptr_slice_elem_val,
|
.ptr_slice_elem_val,
|
||||||
.ptr_elem_val,
|
.ptr_elem_val,
|
||||||
.ptr_ptr_elem_val,
|
.ptr_ptr_elem_val,
|
||||||
|
.shl,
|
||||||
|
.shr,
|
||||||
=> try w.writeBinOp(s, inst),
|
=> try w.writeBinOp(s, inst),
|
||||||
|
|
||||||
.is_null,
|
.is_null,
|
||||||
|
@ -808,6 +808,31 @@ pub fn addCases(ctx: *TestContext) !void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var case = ctx.exeFromCompiledC("shift right + left", .{});
|
||||||
|
case.addCompareOutput(
|
||||||
|
\\pub export fn main() c_int {
|
||||||
|
\\ var i: u32 = 16;
|
||||||
|
\\ assert(i >> 1, 8);
|
||||||
|
\\ return 0;
|
||||||
|
\\}
|
||||||
|
\\fn assert(a: u32, b: u32) void {
|
||||||
|
\\ if (a != b) unreachable;
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
|
|
||||||
|
case.addCompareOutput(
|
||||||
|
\\pub export fn main() c_int {
|
||||||
|
\\ var i: u32 = 16;
|
||||||
|
\\ assert(i << 1, 32);
|
||||||
|
\\ return 0;
|
||||||
|
\\}
|
||||||
|
\\fn assert(a: u32, b: u32) void {
|
||||||
|
\\ if (a != b) unreachable;
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var case = ctx.exeFromCompiledC("inferred error sets", .{});
|
var case = ctx.exeFromCompiledC("inferred error sets", .{});
|
||||||
|
|
||||||
|
@ -28,6 +28,29 @@ pub fn addCases(ctx: *TestContext) !void {
|
|||||||
, "");
|
, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var case = ctx.exeUsingLlvmBackend("shift right + left", linux_x64);
|
||||||
|
|
||||||
|
case.addCompareOutput(
|
||||||
|
\\pub export fn main() void {
|
||||||
|
\\ var i: u32 = 16;
|
||||||
|
\\ assert(i >> 1, 8);
|
||||||
|
\\}
|
||||||
|
\\fn assert(a: u32, b: u32) void {
|
||||||
|
\\ if (a != b) unreachable;
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
|
case.addCompareOutput(
|
||||||
|
\\pub export fn main() void {
|
||||||
|
\\ var i: u32 = 16;
|
||||||
|
\\ assert(i << 1, 32);
|
||||||
|
\\}
|
||||||
|
\\fn assert(a: u32, b: u32) void {
|
||||||
|
\\ if (a != b) unreachable;
|
||||||
|
\\}
|
||||||
|
, "");
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);
|
var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user