mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 16:45:27 +00:00
commit
6a5094872f
@ -94,6 +94,12 @@ pub const Inst = struct {
|
||||
/// Result type is the same as both operands.
|
||||
/// Uses the `bin_op` field.
|
||||
bit_or,
|
||||
/// Shift right. `>>`
|
||||
/// Uses the `bin_op` field.
|
||||
shr,
|
||||
/// Shift left. `<<`
|
||||
/// Uses the `bin_op` field.
|
||||
shl,
|
||||
/// Bitwise XOR. `^`
|
||||
/// Uses the `bin_op` field.
|
||||
xor,
|
||||
@ -445,6 +451,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
||||
.xor,
|
||||
.ptr_add,
|
||||
.ptr_sub,
|
||||
.shr,
|
||||
.shl,
|
||||
=> return air.typeOf(datas[inst].bin_op.lhs),
|
||||
|
||||
.cmp_lt,
|
||||
|
@ -249,6 +249,8 @@ fn analyzeInst(
|
||||
.ptr_slice_elem_val,
|
||||
.ptr_elem_val,
|
||||
.ptr_ptr_elem_val,
|
||||
.shl,
|
||||
.shr,
|
||||
=> {
|
||||
const o = inst_datas[inst].bin_op;
|
||||
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());
|
||||
defer tracy.end();
|
||||
|
||||
_ = block;
|
||||
_ = inst;
|
||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirShl", .{});
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
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 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 {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
_ = inst;
|
||||
return sema.mod.fail(&block.base, sema.src, "TODO implement zirShr", .{});
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
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(
|
||||
@ -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 {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
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 {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
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(
|
||||
|
@ -822,6 +822,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.bit_and => try self.airBitAnd(inst),
|
||||
.bit_or => try self.airBitOr(inst),
|
||||
.xor => try self.airXor(inst),
|
||||
.shr => try self.airShr(inst),
|
||||
.shl => try self.airShl(inst),
|
||||
|
||||
.alloc => try self.airAlloc(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 });
|
||||
}
|
||||
|
||||
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 {
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
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, " | "),
|
||||
.xor => try airBinOp(o, inst, " ^ "),
|
||||
|
||||
.shr => try airBinOp(o, inst, " >> "),
|
||||
.shl => try airBinOp(o, inst, " << "),
|
||||
|
||||
.not => try airNot( o, inst),
|
||||
|
||||
.optional_payload => try airOptionalPayload(o, inst),
|
||||
|
@ -993,6 +993,9 @@ pub const FuncGen = struct {
|
||||
.bit_or, .bool_or => try self.airOr(inst),
|
||||
.xor => try self.airXor(inst),
|
||||
|
||||
.shl => try self.airShl(inst),
|
||||
.shr => try self.airShr(inst),
|
||||
|
||||
.cmp_eq => try self.airCmp(inst, .eq),
|
||||
.cmp_gt => try self.airCmp(inst, .gt),
|
||||
.cmp_gte => try self.airCmp(inst, .gte),
|
||||
@ -1736,6 +1739,41 @@ pub const FuncGen = struct {
|
||||
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 {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
|
@ -290,6 +290,14 @@ pub const Builder = opaque {
|
||||
pub const getInsertBlock = LLVMGetInsertBlock;
|
||||
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;
|
||||
extern fn LLVMBuildCall(
|
||||
*const Builder,
|
||||
@ -381,6 +389,15 @@ pub const Builder = opaque {
|
||||
pub const buildAnd = LLVMBuildAnd;
|
||||
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;
|
||||
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_elem_val,
|
||||
.ptr_ptr_elem_val,
|
||||
.shl,
|
||||
.shr,
|
||||
=> try w.writeBinOp(s, inst),
|
||||
|
||||
.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", .{});
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user