Implement leading and trailing zeroes
This commit is contained in:
parent
b549b6ed49
commit
01f3e5beae
3
TODOLIST
3
TODOLIST
@ -1,6 +1,3 @@
|
|||||||
size
|
|
||||||
trailing zeroes
|
|
||||||
leading zeroes
|
|
||||||
returns inside loops (if conditional)
|
returns inside loops (if conditional)
|
||||||
returns inside loops (else conditional)
|
returns inside loops (else conditional)
|
||||||
returns inside loops (non-conditional)
|
returns inside loops (non-conditional)
|
||||||
|
@ -242,6 +242,52 @@ const Parser = struct{
|
|||||||
});
|
});
|
||||||
return &constant_int.value;
|
return &constant_int.value;
|
||||||
},
|
},
|
||||||
|
.trailing_zeroes => {
|
||||||
|
parser.skip_space(src);
|
||||||
|
parser.expect_character(src, '(');
|
||||||
|
parser.skip_space(src);
|
||||||
|
const value = parser.parse_expression(analyzer, thread, file, ty, .right);
|
||||||
|
parser.skip_space(src);
|
||||||
|
parser.expect_character(src, ')');
|
||||||
|
const tz = thread.trailing_zeroes.append(.{
|
||||||
|
.value = value,
|
||||||
|
.instruction = .{
|
||||||
|
.id = .trailing_zeroes,
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.id = .instruction,
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&tz.instruction);
|
||||||
|
return &tz.instruction.value;
|
||||||
|
},
|
||||||
|
.leading_zeroes => {
|
||||||
|
parser.skip_space(src);
|
||||||
|
parser.expect_character(src, '(');
|
||||||
|
parser.skip_space(src);
|
||||||
|
const value = parser.parse_expression(analyzer, thread, file, ty, .right);
|
||||||
|
parser.skip_space(src);
|
||||||
|
parser.expect_character(src, ')');
|
||||||
|
const lz = thread.leading_zeroes.append(.{
|
||||||
|
.value = value,
|
||||||
|
.instruction = .{
|
||||||
|
.id = .leading_zeroes,
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.id = .instruction,
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&lz.instruction);
|
||||||
|
return &lz.instruction.value;
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1518,6 +1564,14 @@ const Value = struct {
|
|||||||
.integer_compare => {
|
.integer_compare => {
|
||||||
return &instance.threads[value.sema.thread].integers[0].type;
|
return &instance.threads[value.sema.thread].integers[0].type;
|
||||||
},
|
},
|
||||||
|
.trailing_zeroes => {
|
||||||
|
const tz = instruction.get_payload(.trailing_zeroes);
|
||||||
|
return tz.value.get_type();
|
||||||
|
},
|
||||||
|
.leading_zeroes => {
|
||||||
|
const lz = instruction.get_payload(.leading_zeroes);
|
||||||
|
return lz.value.get_type();
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -1582,7 +1636,9 @@ const Keyword = enum{
|
|||||||
|
|
||||||
const Intrinsic = enum{
|
const Intrinsic = enum{
|
||||||
assert,
|
assert,
|
||||||
|
leading_zeroes,
|
||||||
size,
|
size,
|
||||||
|
trailing_zeroes,
|
||||||
trap,
|
trap,
|
||||||
@"unreachable",
|
@"unreachable",
|
||||||
};
|
};
|
||||||
@ -1802,12 +1858,14 @@ const Instruction = struct{
|
|||||||
integer_binary_operation,
|
integer_binary_operation,
|
||||||
integer_compare,
|
integer_compare,
|
||||||
jump,
|
jump,
|
||||||
|
leading_zeroes,
|
||||||
load,
|
load,
|
||||||
local_symbol,
|
local_symbol,
|
||||||
phi,
|
phi,
|
||||||
ret,
|
ret,
|
||||||
ret_void,
|
ret_void,
|
||||||
store,
|
store,
|
||||||
|
trailing_zeroes,
|
||||||
@"unreachable",
|
@"unreachable",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1818,12 +1876,14 @@ const Instruction = struct{
|
|||||||
.integer_binary_operation = IntegerBinaryOperation,
|
.integer_binary_operation = IntegerBinaryOperation,
|
||||||
.integer_compare = IntegerCompare,
|
.integer_compare = IntegerCompare,
|
||||||
.jump = Jump,
|
.jump = Jump,
|
||||||
|
.leading_zeroes = LeadingZeroes,
|
||||||
.local_symbol = LocalSymbol,
|
.local_symbol = LocalSymbol,
|
||||||
.load = Load,
|
.load = Load,
|
||||||
.phi = Phi,
|
.phi = Phi,
|
||||||
.ret = Return,
|
.ret = Return,
|
||||||
.ret_void = void,
|
.ret_void = void,
|
||||||
.store = Store,
|
.store = Store,
|
||||||
|
.trailing_zeroes = TrailingZeroes,
|
||||||
.@"unreachable" = Unreachable,
|
.@"unreachable" = Unreachable,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1950,6 +2010,16 @@ fn get_power_of_two_byte_count_from_bit_count(bit_count: u32) u32 {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LeadingZeroes = struct{
|
||||||
|
instruction: Instruction,
|
||||||
|
value: *Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TrailingZeroes = struct{
|
||||||
|
instruction: Instruction,
|
||||||
|
value: *Value,
|
||||||
|
};
|
||||||
|
|
||||||
const Thread = struct{
|
const Thread = struct{
|
||||||
arena: *Arena = undefined,
|
arena: *Arena = undefined,
|
||||||
functions: PinnedArray(Function) = .{},
|
functions: PinnedArray(Function) = .{},
|
||||||
@ -1976,6 +2046,8 @@ const Thread = struct{
|
|||||||
argument_symbols: PinnedArray(ArgumentSymbol) = .{},
|
argument_symbols: PinnedArray(ArgumentSymbol) = .{},
|
||||||
global_variables: PinnedArray(GlobalVariable) = .{},
|
global_variables: PinnedArray(GlobalVariable) = .{},
|
||||||
unreachables: PinnedArray(Unreachable) = .{},
|
unreachables: PinnedArray(Unreachable) = .{},
|
||||||
|
leading_zeroes: PinnedArray(LeadingZeroes) = .{},
|
||||||
|
trailing_zeroes: PinnedArray(TrailingZeroes) = .{},
|
||||||
analyzed_file_count: u32 = 0,
|
analyzed_file_count: u32 = 0,
|
||||||
assigned_file_count: u32 = 0,
|
assigned_file_count: u32 = 0,
|
||||||
llvm: struct {
|
llvm: struct {
|
||||||
@ -1984,6 +2056,9 @@ const Thread = struct{
|
|||||||
attributes: LLVM.Attributes,
|
attributes: LLVM.Attributes,
|
||||||
target_machine: *LLVM.Target.Machine,
|
target_machine: *LLVM.Target.Machine,
|
||||||
object: ?[]const u8 = null,
|
object: ?[]const u8 = null,
|
||||||
|
intrinsic_ids: std.EnumArray(LLVMIntrinsic, LLVM.Value.IntrinsicID),
|
||||||
|
intrinsic_id_map: PinnedHashMap([]const u8, LLVM.Value.IntrinsicID) = .{},
|
||||||
|
intrinsic_function_map: PinnedHashMap(LLVMIntrinsic.Parameters, *LLVM.Value.Constant.Function) = .{},
|
||||||
} = undefined,
|
} = undefined,
|
||||||
integers: [128]Type.Integer = blk: {
|
integers: [128]Type.Integer = blk: {
|
||||||
var integers: [128]Type.Integer = undefined;
|
var integers: [128]Type.Integer = undefined;
|
||||||
@ -2054,6 +2129,16 @@ const Thread = struct{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const LLVMIntrinsic = enum{
|
||||||
|
leading_zeroes,
|
||||||
|
trailing_zeroes,
|
||||||
|
|
||||||
|
const Parameters = struct{
|
||||||
|
id: LLVM.Value.IntrinsicID,
|
||||||
|
types: []const *LLVM.Type,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const LLVMFile = struct {
|
const LLVMFile = struct {
|
||||||
file: *LLVM.DebugInfo.File,
|
file: *LLVM.DebugInfo.File,
|
||||||
compile_unit: *LLVM.DebugInfo.CompileUnit,
|
compile_unit: *LLVM.DebugInfo.CompileUnit,
|
||||||
@ -3117,10 +3202,13 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
.module = module,
|
.module = module,
|
||||||
.attributes = attributes,
|
.attributes = attributes,
|
||||||
.target_machine = target_machine,
|
.target_machine = target_machine,
|
||||||
|
.intrinsic_ids = @TypeOf(thread.llvm.intrinsic_ids).init(.{
|
||||||
|
.leading_zeroes = llvm_get_intrinsic_id("llvm.ctlz"),
|
||||||
|
.trailing_zeroes = llvm_get_intrinsic_id("llvm.cttz"),
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
const debug_info = false;
|
const debug_info = false;
|
||||||
|
|
||||||
|
|
||||||
for (thread.external_functions.slice()) |*nat_function| {
|
for (thread.external_functions.slice()) |*nat_function| {
|
||||||
_ = llvm_get_function(thread, nat_function, true);
|
_ = llvm_get_function(thread, nat_function, true);
|
||||||
}
|
}
|
||||||
@ -3329,6 +3417,38 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
const ur = builder.createUnreachable();
|
const ur = builder.createUnreachable();
|
||||||
break :block ur.toValue();
|
break :block ur.toValue();
|
||||||
},
|
},
|
||||||
|
.leading_zeroes => block: {
|
||||||
|
const leading_zeroes = instruction.get_payload(.leading_zeroes);
|
||||||
|
const v = llvm_get_value(thread, leading_zeroes.value);
|
||||||
|
const v_type = v.getType();
|
||||||
|
const lz_id = thread.llvm.intrinsic_ids.get(.leading_zeroes);
|
||||||
|
const parameters = LLVMIntrinsic.Parameters{
|
||||||
|
.id = lz_id,
|
||||||
|
.types = &.{v_type},
|
||||||
|
};
|
||||||
|
const intrinsic_function = llvm_get_intrinsic_function(thread, parameters);
|
||||||
|
const intrinsic_function_type = intrinsic_function.getType();
|
||||||
|
const is_poison = context.getConstantInt(1, 0, false);
|
||||||
|
const args: []const *LLVM.Value = &.{v, is_poison.toValue()};
|
||||||
|
const call_i = builder.createCall(intrinsic_function_type, intrinsic_function.toValue(), args.ptr, args.len, "", "".len, null);
|
||||||
|
break :block call_i.toValue();
|
||||||
|
},
|
||||||
|
.trailing_zeroes => block: {
|
||||||
|
const trailing_zeroes = instruction.get_payload(.trailing_zeroes);
|
||||||
|
const v = llvm_get_value(thread, trailing_zeroes.value);
|
||||||
|
const v_type = v.getType();
|
||||||
|
const tz_id = thread.llvm.intrinsic_ids.get(.trailing_zeroes);
|
||||||
|
const parameters = LLVMIntrinsic.Parameters{
|
||||||
|
.id = tz_id,
|
||||||
|
.types = &.{v_type},
|
||||||
|
};
|
||||||
|
const intrinsic_function = llvm_get_intrinsic_function(thread, parameters);
|
||||||
|
const intrinsic_function_type = intrinsic_function.getType();
|
||||||
|
const is_poison = context.getConstantInt(1, 0, false);
|
||||||
|
const args: []const *LLVM.Value = &.{v, is_poison.toValue()};
|
||||||
|
const call_i = builder.createCall(intrinsic_function_type, intrinsic_function.toValue(), args.ptr, args.len, "", "".len, null);
|
||||||
|
break :block call_i.toValue();
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -3434,6 +3554,20 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn llvm_get_intrinsic_id(intrinsic: []const u8) LLVM.Value.IntrinsicID{
|
||||||
|
const intrinsic_id = LLVM.lookupIntrinsic(intrinsic.ptr, intrinsic.len);
|
||||||
|
assert(intrinsic_id != .none);
|
||||||
|
return intrinsic_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn llvm_get_intrinsic_function(thread: *Thread, parameters: LLVMIntrinsic.Parameters) *LLVM.Value.Constant.Function{
|
||||||
|
if (thread.llvm.intrinsic_function_map.get(parameters)) |llvm| return llvm else {
|
||||||
|
const intrinsic_function = thread.llvm.module.getIntrinsicDeclaration(parameters.id, parameters.types.ptr, parameters.types.len);
|
||||||
|
thread.llvm.intrinsic_function_map.put_no_clobber(parameters, intrinsic_function);
|
||||||
|
return intrinsic_function;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn llvm_get_value(thread: *Thread, value: *Value) *LLVM.Value {
|
fn llvm_get_value(thread: *Thread, value: *Value) *LLVM.Value {
|
||||||
if (value.llvm) |llvm| {
|
if (value.llvm) |llvm| {
|
||||||
assert(value.sema.thread == thread.get_index());
|
assert(value.sema.thread == thread.get_index());
|
||||||
|
7
retest/standalone/leading_zeroes/main.nat
Normal file
7
retest/standalone/leading_zeroes/main.nat
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fn[cc(.c)] main[export]() s32 {
|
||||||
|
>a: s32 = 0xffffffff;
|
||||||
|
#assert(#leading_zeroes(a) == 0);
|
||||||
|
>b: s32 = 0x1fffffff;
|
||||||
|
#assert(#leading_zeroes(b) == 3);
|
||||||
|
return 0;
|
||||||
|
}
|
7
retest/standalone/trailing_zeroes/main.nat
Normal file
7
retest/standalone/trailing_zeroes/main.nat
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fn[cc(.c)] main[export]() s32 {
|
||||||
|
>a: s32 = 7;
|
||||||
|
#assert(#trailing_zeroes(a) == 0);
|
||||||
|
>b: s32 = 8;
|
||||||
|
#assert(#trailing_zeroes(b) == 3);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user