mirror of
https://github.com/LLVMParty/llvm-nanobind
synced 2026-06-21 13:43:38 +00:00
@@ -265,6 +265,12 @@ This section captures guard preconditions for wrapper classes other than
|
||||
- `set_body` requires identified opaque struct type (not literal, not already
|
||||
non-opaque).
|
||||
|
||||
### Type factory aliases
|
||||
|
||||
- `types` is available on `Context`, `Module`, `Function`, `BasicBlock`, and `Value`.
|
||||
- All aliases for objects in the same context compare equal:
|
||||
`ctx.types == mod.types == fn.types == bb.types == value.types`.
|
||||
|
||||
### BasicBlock (`llvm.BasicBlock`)
|
||||
|
||||
- `terminator` requires the block to have a terminator.
|
||||
@@ -295,6 +301,8 @@ This section captures guard preconditions for wrapper classes other than
|
||||
- `param_attributes(i)` for parameter attributes, using a 0-based Python index.
|
||||
- Use `llvm.Attribute.enum/type/string(...)` or `slot.add("noreturn")`.
|
||||
- Use `llvm.Attribute.memory(ctx, "none")` or `slot.add_memory("read")` for `memory(...)` effects without raw encoded integers.
|
||||
- `create_builder()` positions in the function entry block and creates an
|
||||
`entry` block when the function has no blocks yet.
|
||||
- `block_address` requires block ownership by that function.
|
||||
Prefer `bb.block_address()` when the function can be inferred.
|
||||
- Parent navigation:
|
||||
@@ -308,6 +316,9 @@ This section captures guard preconditions for wrapper classes other than
|
||||
- Positioning:
|
||||
- `position_before(inst)` requires an instruction attached to a block.
|
||||
- `position_at(bb, inst)` requires `inst` to be an instruction in `bb`.
|
||||
- Memory allocation:
|
||||
- `alloca(ty, name="")` creates a scalar alloca.
|
||||
- `alloca(ty, count, name="")` creates an array alloca.
|
||||
- Instruction-only insertion helpers:
|
||||
- `insert_into_builder_with_name(instr)` requires instruction value.
|
||||
- `add_metadata_to_inst(instr)` requires instruction value.
|
||||
|
||||
@@ -288,7 +288,7 @@ with builder.debug_location(loc):
|
||||
- Module flags add/get/key iteration.
|
||||
- Debug-location context manager.
|
||||
- DIBuilder recipes for file, compile unit, function, and local variable.
|
||||
- Removed raw APIs stay absent from the public surface.
|
||||
- Public surface is reviewed during API changes.
|
||||
|
||||
## API audit process
|
||||
|
||||
@@ -297,8 +297,7 @@ After each phase:
|
||||
1. Rebuild to regenerate `.pyi`.
|
||||
2. Review new public symbols.
|
||||
3. Confirm examples express user tasks directly.
|
||||
4. Add intentionally removed symbols to `tests/regressions/test_api_surface_cleanup.py`.
|
||||
5. Keep advanced lower-level APIs when they correspond to useful LLVM controls.
|
||||
4. Keep advanced lower-level APIs when they correspond to useful LLVM controls.
|
||||
|
||||
## Suggested implementation order
|
||||
|
||||
|
||||
+115
-9
@@ -1017,6 +1017,16 @@ struct LLVMTypeFactoryWrapper {
|
||||
throw LLVMMemoryError("TypeFactory used after context was destroyed");
|
||||
}
|
||||
|
||||
bool operator==(const LLVMTypeFactoryWrapper &other) const {
|
||||
check_valid();
|
||||
other.check_valid();
|
||||
return m_ctx_ref == other.m_ctx_ref;
|
||||
}
|
||||
|
||||
bool operator!=(const LLVMTypeFactoryWrapper &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Fixed-width integer types (properties)
|
||||
// =========================================================================
|
||||
@@ -3404,6 +3414,17 @@ struct LLVMValueWrapper {
|
||||
|
||||
LLVMMetadataMapWrapper metadata() const;
|
||||
|
||||
LLVMTypeFactoryWrapper types() const {
|
||||
check_valid();
|
||||
LLVMTypeRef ty = LLVMTypeOf(m_ref);
|
||||
if (!ty)
|
||||
throw LLVMAssertionError("Value has no type context");
|
||||
LLVMContextRef ctx_ref = LLVMGetTypeContext(ty);
|
||||
if (!ctx_ref)
|
||||
throw LLVMAssertionError("Value has no type context");
|
||||
return LLVMTypeFactoryWrapper(ctx_ref, m_context_token);
|
||||
}
|
||||
|
||||
// Unified set_metadata - works for both instructions and globals
|
||||
// Declared here, implemented after LLVMMetadataWrapper
|
||||
// Takes a context for converting metadata to value (needed for instructions)
|
||||
@@ -3901,6 +3922,17 @@ struct LLVMBasicBlockWrapper {
|
||||
return result;
|
||||
}
|
||||
|
||||
LLVMTypeFactoryWrapper types() const {
|
||||
check_valid();
|
||||
LLVMTypeRef ty = LLVMTypeOf(LLVMBasicBlockAsValue(m_ref));
|
||||
if (!ty)
|
||||
throw LLVMAssertionError("BasicBlock has no type context");
|
||||
LLVMContextRef ctx_ref = LLVMGetTypeContext(ty);
|
||||
if (!ctx_ref)
|
||||
throw LLVMAssertionError("BasicBlock has no type context");
|
||||
return LLVMTypeFactoryWrapper(ctx_ref, m_context_token);
|
||||
}
|
||||
|
||||
// Create a builder positioned at the end of this basic block, or before the
|
||||
// first non-PHI instruction when requested.
|
||||
LLVMBuilderManager *create_builder(bool first_non_phi = false) const;
|
||||
@@ -4106,6 +4138,12 @@ struct LLVMFunctionWrapper : LLVMValueWrapper {
|
||||
// Get the context this function belongs to (derived via module)
|
||||
LLVMContextWrapper *context() const;
|
||||
|
||||
LLVMTypeFactoryWrapper types() const { return LLVMValueWrapper::types(); }
|
||||
|
||||
// Create a builder positioned at the end of this function's entry block.
|
||||
// If the function has no blocks yet, create an entry block first.
|
||||
LLVMBuilderManager *create_builder(bool first_non_phi = false) const;
|
||||
|
||||
// =========================================================================
|
||||
// Function verification (Analysis.h)
|
||||
// =========================================================================
|
||||
@@ -5303,14 +5341,14 @@ struct LLVMBuilderWrapper : NoMoveCopy {
|
||||
m_context_token);
|
||||
}
|
||||
|
||||
LLVMValueWrapper build_array_alloca(const LLVMTypeWrapper &ty,
|
||||
const LLVMValueWrapper &size,
|
||||
const std::string &name = "") {
|
||||
LLVMValueWrapper build_alloca(const LLVMTypeWrapper &ty,
|
||||
const LLVMValueWrapper &count,
|
||||
const std::string &name = "") {
|
||||
check_valid();
|
||||
ty.check_valid();
|
||||
size.check_valid();
|
||||
count.check_valid();
|
||||
return LLVMValueWrapper(
|
||||
LLVMBuildArrayAlloca(m_ref, ty.m_ref, size.m_ref, name.c_str()),
|
||||
LLVMBuildArrayAlloca(m_ref, ty.m_ref, count.m_ref, name.c_str()),
|
||||
m_context_token);
|
||||
}
|
||||
|
||||
@@ -6854,6 +6892,11 @@ struct LLVMModuleWrapper : NoMoveCopy {
|
||||
LLVMNamedMetadataMapWrapper named_metadata() const;
|
||||
LLVMModuleFlagsWrapper module_flags() const;
|
||||
|
||||
LLVMTypeFactoryWrapper types() const {
|
||||
check_valid();
|
||||
return LLVMTypeFactoryWrapper(m_ctx_ref, m_context_token);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Module API Refactor: Methods moved from global functions
|
||||
// =========================================================================
|
||||
@@ -7564,6 +7607,25 @@ LLVMBuilderManager *LLVMBasicBlockWrapper::create_builder(
|
||||
return manager;
|
||||
}
|
||||
|
||||
LLVMBuilderManager *LLVMFunctionWrapper::create_builder(
|
||||
bool first_non_phi) const {
|
||||
check_valid();
|
||||
LLVMModuleRef mod_ref = LLVMGetGlobalParent(m_ref);
|
||||
if (!mod_ref)
|
||||
throw LLVMAssertionError("create_builder requires a function in a module");
|
||||
|
||||
LLVMBasicBlockRef entry = nullptr;
|
||||
if (LLVMCountBasicBlocks(m_ref) == 0) {
|
||||
LLVMContextRef ctx_ref = LLVMGetModuleContext(mod_ref);
|
||||
entry = LLVMAppendBasicBlockInContext(ctx_ref, m_ref, "entry");
|
||||
} else {
|
||||
entry = LLVMGetEntryBasicBlock(m_ref);
|
||||
}
|
||||
|
||||
LLVMBasicBlockWrapper entry_wrapper(entry, m_context_token);
|
||||
return entry_wrapper.create_builder(first_non_phi);
|
||||
}
|
||||
|
||||
LLVMBuilderManager *LLVMValueWrapper::create_builder(bool before_dbg) const {
|
||||
check_valid();
|
||||
if (!is_a_instruction())
|
||||
@@ -14150,6 +14212,10 @@ Alias for `.block`.
|
||||
|
||||
<sub>C API: LLVMGetTypeContext</sub>)",
|
||||
nb::rv_policy::take_ownership)
|
||||
.def_prop_ro("types", &LLVMValueWrapper::types,
|
||||
R"(Type factory for this value's context.
|
||||
|
||||
<sub>C API: LLVMTypeOf, LLVMGetTypeContext</sub>)")
|
||||
// BasicBlock properties
|
||||
.def_prop_ro("normal_dest", &LLVMValueWrapper::get_normal_dest,
|
||||
R"(Get normal destination.
|
||||
@@ -14425,6 +14491,10 @@ Returns None when the block has no non-PHI instruction.)")
|
||||
|
||||
<sub>C API: LLVMGetTypeContext</sub>)",
|
||||
nb::rv_policy::take_ownership)
|
||||
.def_prop_ro("types", &LLVMBasicBlockWrapper::types,
|
||||
R"(Type factory for this basic block's context.
|
||||
|
||||
<sub>C API: LLVMBasicBlockAsValue, LLVMTypeOf, LLVMGetTypeContext</sub>)")
|
||||
.def_prop_ro("successors", &LLVMBasicBlockWrapper::successors,
|
||||
R"(Successor blocks.
|
||||
|
||||
@@ -14653,6 +14723,24 @@ Valid when:
|
||||
|
||||
<sub>C API: LLVMGetTypeContext</sub>)",
|
||||
nb::rv_policy::take_ownership)
|
||||
.def_prop_ro("types", &LLVMFunctionWrapper::types,
|
||||
R"(Type factory for this function's context.
|
||||
|
||||
<sub>C API: LLVMTypeOf, LLVMGetTypeContext</sub>)")
|
||||
.def("create_builder", &LLVMFunctionWrapper::create_builder,
|
||||
nb::kw_only(), "first_non_phi"_a = false,
|
||||
nb::rv_policy::take_ownership,
|
||||
R"(Create a Builder in this function's entry block.
|
||||
|
||||
If this function has no basic blocks yet, creates an entry block first.
|
||||
|
||||
With `first_non_phi=True`, positions before the first non-PHI instruction in
|
||||
the entry block. If the entry block has no non-PHI instruction, the builder is
|
||||
positioned at the end of the block.
|
||||
|
||||
Returns a BuilderManager for use with Python's 'with' statement.
|
||||
|
||||
<sub>C API: LLVMAppendBasicBlockInContext, LLVMCreateBuilderInContext</sub>)")
|
||||
// Verification
|
||||
.def("verify", &LLVMFunctionWrapper::verify,
|
||||
R"(Verify function.
|
||||
@@ -14929,12 +15017,18 @@ Use with a with-statement:
|
||||
|
||||
<sub>C API: LLVMBuildBinOp</sub>)")
|
||||
// Memory
|
||||
.def("alloca", &LLVMBuilderWrapper::build_alloca, "ty"_a, "name"_a = "",
|
||||
R"(Build alloca.
|
||||
.def("alloca",
|
||||
nb::overload_cast<const LLVMTypeWrapper &, const std::string &>(
|
||||
&LLVMBuilderWrapper::build_alloca),
|
||||
"ty"_a, "name"_a = "",
|
||||
R"(Build scalar alloca.
|
||||
|
||||
<sub>C API: LLVMBuildAlloca</sub>)")
|
||||
.def("array_alloca", &LLVMBuilderWrapper::build_array_alloca, "ty"_a,
|
||||
"size"_a, "name"_a = "",
|
||||
.def("alloca",
|
||||
nb::overload_cast<const LLVMTypeWrapper &, const LLVMValueWrapper &,
|
||||
const std::string &>(
|
||||
&LLVMBuilderWrapper::build_alloca),
|
||||
"ty"_a, "count"_a, "name"_a = "",
|
||||
R"(Build array alloca.
|
||||
|
||||
<sub>C API: LLVMBuildArrayAlloca</sub>)")
|
||||
@@ -15769,6 +15863,10 @@ Example:
|
||||
nb::rv_policy::take_ownership,
|
||||
R"(Get the context for this module.
|
||||
|
||||
<sub>C API: LLVMGetModuleContext</sub>)")
|
||||
.def_prop_ro("types", &LLVMModuleWrapper::types,
|
||||
R"(Type factory for this module's context.
|
||||
|
||||
<sub>C API: LLVMGetModuleContext</sub>)")
|
||||
.def_prop_rw("is_new_dbg_info_format",
|
||||
&LLVMModuleWrapper::is_new_dbg_info_format,
|
||||
@@ -15863,6 +15961,14 @@ Returns a BuilderManager for use with Python's 'with' statement.
|
||||
|
||||
// TypeFactory wrapper (property-based type namespace)
|
||||
nb::class_<LLVMTypeFactoryWrapper>(m, "TypeFactory")
|
||||
.def("__eq__", &LLVMTypeFactoryWrapper::operator==, "other"_a,
|
||||
R"(Return True when both type factories use the same LLVM context.
|
||||
|
||||
<sub>C API limitation: compares stored LLVMContextRef pointers</sub>)")
|
||||
.def("__ne__", &LLVMTypeFactoryWrapper::operator!=, "other"_a,
|
||||
R"(Return True when type factories use different LLVM contexts.
|
||||
|
||||
<sub>C API limitation: compares stored LLVMContextRef pointers</sub>)")
|
||||
// Fixed-width integer types
|
||||
.def_prop_ro("i1", &LLVMTypeFactoryWrapper::i1,
|
||||
R"(1-bit int.
|
||||
|
||||
@@ -1,326 +0,0 @@
|
||||
"""
|
||||
Regression coverage for API surface cleanup helpers.
|
||||
|
||||
Covers:
|
||||
- Module add_* reuse_existing=True defaults and explicit raw insertion escape hatch
|
||||
- Named struct reuse_existing=True defaults and explicit raw insertion escape hatch
|
||||
- New member/factory APIs that replace module-level helpers
|
||||
- Builder parent navigation helpers and Module.create_builder()
|
||||
"""
|
||||
|
||||
import llvm
|
||||
|
||||
|
||||
def expect_raises(fn, message_part: str) -> None:
|
||||
try:
|
||||
fn()
|
||||
except Exception as exc:
|
||||
assert message_part in str(exc), str(exc)
|
||||
else:
|
||||
raise AssertionError("expected exception")
|
||||
|
||||
|
||||
def test_module_add_reuse_existing_semantics() -> None:
|
||||
with llvm.create_context() as ctx:
|
||||
i32 = ctx.types.i32
|
||||
i64 = ctx.types.i64
|
||||
void = ctx.types.void
|
||||
fn_ty = ctx.types.function(void, [])
|
||||
other_fn_ty = ctx.types.function(i32, [])
|
||||
resolver_ty = ctx.types.function(i32, [])
|
||||
|
||||
with ctx.create_module("reuse_existing") as mod:
|
||||
fn = mod.add_function("f", fn_ty)
|
||||
assert mod.add_function("f", fn_ty) == fn
|
||||
assert len([f for f in mod.functions if f.name.startswith("f")]) == 1
|
||||
expect_raises(lambda: mod.add_function("f", other_fn_ty), "different type")
|
||||
raw_fn = mod.add_function("f", fn_ty, reuse_existing=False)
|
||||
assert raw_fn.name != "f"
|
||||
|
||||
g = mod.add_global(i32, "g")
|
||||
assert mod.add_global(i32, "g") == g
|
||||
expect_raises(lambda: mod.add_global(i64, "g"), "different type")
|
||||
expect_raises(
|
||||
lambda: mod.add_global_in_address_space(i32, "g", 1),
|
||||
"address space",
|
||||
)
|
||||
raw_g = mod.add_global(i32, "g", reuse_existing=False)
|
||||
assert raw_g.name != "g"
|
||||
|
||||
expect_raises(lambda: mod.add_function("g", fn_ty), "global variable")
|
||||
expect_raises(lambda: mod.add_global(i32, "f"), "function")
|
||||
|
||||
alias = mod.add_alias(i32, 0, g, "alias")
|
||||
assert mod.add_alias(i32, 0, g, "alias") == alias
|
||||
expect_raises(lambda: mod.add_alias(i64, 0, g, "alias"), "different type")
|
||||
raw_alias = mod.add_alias(i32, 0, g, "alias", reuse_existing=False)
|
||||
assert raw_alias.name != "alias"
|
||||
|
||||
resolver = mod.add_function("resolver", resolver_ty)
|
||||
other_resolver = mod.add_function("other_resolver", resolver_ty)
|
||||
ifunc = mod.add_global_ifunc("ifunc", resolver_ty, 0, resolver)
|
||||
assert mod.add_global_ifunc("ifunc", resolver_ty, 0, resolver) == ifunc
|
||||
expect_raises(
|
||||
lambda: mod.add_global_ifunc("ifunc", resolver_ty, 1, resolver),
|
||||
"address space",
|
||||
)
|
||||
expect_raises(
|
||||
lambda: mod.add_global_ifunc("ifunc", resolver_ty, 0, other_resolver),
|
||||
"different resolver",
|
||||
)
|
||||
raw_ifunc = mod.add_global_ifunc(
|
||||
"ifunc", resolver_ty, 0, resolver, reuse_existing=False
|
||||
)
|
||||
assert raw_ifunc.name != "ifunc"
|
||||
|
||||
|
||||
def test_named_struct_reuse_existing_semantics() -> None:
|
||||
with llvm.create_context() as ctx:
|
||||
i32 = ctx.types.i32
|
||||
i64 = ctx.types.i64
|
||||
|
||||
pair = ctx.types.struct("Pair", [i32, i64], packed=False)
|
||||
assert pair.struct_name == "Pair"
|
||||
assert not pair.is_opaque_struct
|
||||
assert ctx.types.struct("Pair", [i32, i64], packed=False) == pair
|
||||
expect_raises(
|
||||
lambda: ctx.types.struct("Pair", [i32], packed=False),
|
||||
"different body",
|
||||
)
|
||||
expect_raises(
|
||||
lambda: ctx.types.struct("Pair", [i32, i64], packed=True),
|
||||
"different packing",
|
||||
)
|
||||
|
||||
raw_pair = ctx.types.struct(
|
||||
"Pair", [i32, i64], packed=False, reuse_existing=False
|
||||
)
|
||||
assert raw_pair != pair
|
||||
assert raw_pair.struct_name != "Pair"
|
||||
|
||||
forward = ctx.types.opaque_struct("Forward")
|
||||
assert forward.is_opaque_struct
|
||||
assert ctx.types.opaque_struct("Forward") == forward
|
||||
completed = ctx.types.struct("Forward", [i32])
|
||||
assert completed == forward
|
||||
assert not completed.is_opaque_struct
|
||||
|
||||
raw_forward = ctx.types.opaque_struct("Forward", reuse_existing=False)
|
||||
assert raw_forward != forward
|
||||
assert raw_forward.struct_name != "Forward"
|
||||
|
||||
|
||||
def test_member_factories_and_builder_navigation() -> None:
|
||||
removed_globals = [
|
||||
"AttributeFunctionIndex",
|
||||
"AttributeReturnIndex",
|
||||
"last_enum_attribute_kind",
|
||||
"block_address",
|
||||
"const_data_array",
|
||||
"const_gep_with_no_wrap_flags",
|
||||
"const_int_of_arbitrary_precision",
|
||||
"const_ptr_auth",
|
||||
"const_string",
|
||||
"const_struct",
|
||||
"const_vector",
|
||||
"create_binary_from_bytes",
|
||||
"create_binary_from_file",
|
||||
"create_disasm_cpu_features",
|
||||
"create_target_data",
|
||||
"create_target_machine",
|
||||
"di_file_get_directory",
|
||||
"di_file_get_filename",
|
||||
"di_file_get_source",
|
||||
"di_global_variable_expression_get_expression",
|
||||
"di_global_variable_expression_get_variable",
|
||||
"di_location_get_column",
|
||||
"di_location_get_inlined_at",
|
||||
"di_location_get_line",
|
||||
"di_location_get_scope",
|
||||
"di_scope_get_file",
|
||||
"di_subprogram_get_line",
|
||||
"di_subprogram_replace_type",
|
||||
"di_type_get_name",
|
||||
"di_variable_get_file",
|
||||
"di_variable_get_line",
|
||||
"di_variable_get_scope",
|
||||
"dibuilder_create_debug_location",
|
||||
"get_cast_opcode",
|
||||
"get_debug_metadata_version",
|
||||
"get_default_target_triple",
|
||||
"get_first_dbg_record",
|
||||
"get_host_cpu_features",
|
||||
"get_host_cpu_name",
|
||||
"get_inline_asm",
|
||||
"get_md_kind_id",
|
||||
"initialize_all_asm_parsers",
|
||||
"initialize_all_asm_printers",
|
||||
"initialize_all_disassemblers",
|
||||
"initialize_all_target_infos",
|
||||
"initialize_all_target_mcs",
|
||||
"initialize_all_targets",
|
||||
"initialize_native_asm_parser",
|
||||
"initialize_native_asm_printer",
|
||||
"initialize_native_disassembler",
|
||||
"initialize_native_target",
|
||||
"get_di_node_tag",
|
||||
"get_last_dbg_record",
|
||||
"get_last_enum_attribute_kind",
|
||||
"get_module_debug_metadata_version",
|
||||
"get_next_dbg_record",
|
||||
"get_previous_dbg_record",
|
||||
"get_target_from_name",
|
||||
"get_target_from_triple",
|
||||
"intrinsic_get_type",
|
||||
"lookup_enum_attribute_kind",
|
||||
"replace_md_node_operand_with",
|
||||
"run_passes",
|
||||
"strip_module_debug_info",
|
||||
"NamedMDNode",
|
||||
"ValueMetadataEntries",
|
||||
]
|
||||
for name in removed_globals:
|
||||
assert not hasattr(llvm, name), name
|
||||
|
||||
removed_class_methods = {
|
||||
llvm.Context: [
|
||||
"get_diagnostics",
|
||||
"get_md_kind_id",
|
||||
"create_debug_location",
|
||||
"create_enum_attribute",
|
||||
"create_string_attribute",
|
||||
"create_type_attribute",
|
||||
],
|
||||
llvm.Module: [
|
||||
"get_verification_error",
|
||||
"first_named_metadata",
|
||||
"last_named_metadata",
|
||||
"get_named_metadata",
|
||||
"add_named_metadata",
|
||||
"get_named_metadata_num_operands",
|
||||
"get_named_metadata_operands",
|
||||
"add_named_metadata_operand",
|
||||
"add_module_flag",
|
||||
"get_module_flag",
|
||||
],
|
||||
llvm.Function: [
|
||||
"get_personality_fn",
|
||||
"set_personality_fn",
|
||||
"get_gc",
|
||||
"set_gc",
|
||||
"get_attribute_count",
|
||||
"get_enum_attribute",
|
||||
"add_attribute",
|
||||
"get_attributes",
|
||||
"get_string_attribute",
|
||||
"remove_enum_attribute",
|
||||
"remove_string_attribute",
|
||||
],
|
||||
llvm.Attribute: ["kind"],
|
||||
llvm.AttributeAccessor: ["get_enum", "remove_enum"],
|
||||
llvm.DIBuilder: ["create_file", "create_compile_unit"],
|
||||
llvm.Metadata: ["as_value", "string_value", "__len__", "__getitem__", "__iter__"],
|
||||
llvm.Value: [
|
||||
"set_constant",
|
||||
"set_comdat",
|
||||
"set_thread_local",
|
||||
"set_externally_initialized",
|
||||
"set_volatile",
|
||||
"set_inst_alignment",
|
||||
"set_global_ifunc_resolver",
|
||||
"set_personality_fn",
|
||||
"set_prefix_data",
|
||||
"set_prologue_data",
|
||||
"set_nsw",
|
||||
"set_nuw",
|
||||
"set_exact",
|
||||
"set_nneg",
|
||||
"set_is_disjoint",
|
||||
"set_icmp_same_sign",
|
||||
"set_ordering",
|
||||
"set_atomic_sync_scope_id",
|
||||
"set_weak",
|
||||
"set_tail_call_kind",
|
||||
"set_called_operand",
|
||||
"set_cleanup",
|
||||
"set_fast_math_flags",
|
||||
"get_callsite_attribute_count",
|
||||
"get_callsite_enum_attribute",
|
||||
"add_callsite_attribute",
|
||||
"set_metadata",
|
||||
"global_copy_all_metadata",
|
||||
"instruction_get_all_metadata_other_than_debug_loc",
|
||||
],
|
||||
}
|
||||
for cls, names in removed_class_methods.items():
|
||||
for name in names:
|
||||
assert not hasattr(cls, name), f"{cls.__name__}.{name}"
|
||||
|
||||
assert isinstance(llvm.default_target_triple, str)
|
||||
assert isinstance(llvm.host_cpu_name, str)
|
||||
assert isinstance(llvm.host_cpu_features, str)
|
||||
assert isinstance(llvm.debug_metadata_version, int)
|
||||
|
||||
with llvm.create_context() as ctx:
|
||||
i32 = ctx.types.i32
|
||||
i64 = ctx.types.i64
|
||||
ptr = ctx.types.ptr
|
||||
fn_ty = ctx.types.function(i32, [])
|
||||
|
||||
assert i64.constant([1]).const_zext_value == 1
|
||||
assert i32.vector_const([i32.constant(1), i32.constant(2)]).is_constant
|
||||
assert i32.constant(1).get_cast_opcode(False, i64, False) == llvm.Opcode.ZExt
|
||||
assert ctx.get_intrinsic_type(llvm.lookup_intrinsic_id("llvm.memcpy"), [ptr, ptr, i64]).kind == llvm.TypeKind.Function
|
||||
asm_ty = ctx.types.function(ctx.types.void, [])
|
||||
assert asm_ty.inline_asm("nop", "", False, False, llvm.InlineAsmDialect.ATT, False).is_inline_asm
|
||||
|
||||
with ctx.create_module("surface") as mod:
|
||||
fn = mod.add_function("f", fn_ty)
|
||||
bb = fn.append_basic_block("entry")
|
||||
assert bb.block_address().is_constant
|
||||
|
||||
with mod.create_builder(bb) as builder:
|
||||
assert builder.function == fn
|
||||
assert builder.module == mod
|
||||
assert builder.context is not None
|
||||
ret = builder.ret(i32.constant(0))
|
||||
expect_raises(lambda: ret.has_dbg_records, "LLVM-C has no safe")
|
||||
|
||||
with mod.create_builder(ret) as before_ret:
|
||||
assert before_ret.insert_block == bb
|
||||
|
||||
assert not hasattr(mod, "get_or_insert_named_metadata")
|
||||
named_md = mod.named_metadata["llvm.nanobind.surface"]
|
||||
assert mod.named_metadata["llvm.nanobind.surface"] is not None
|
||||
assert len(named_md) == 0
|
||||
|
||||
assert not hasattr(mod, "get_or_insert_comdat")
|
||||
comdat = mod.add_comdat("surface_comdat")
|
||||
comdat.selection_kind = llvm.ComdatSelectionKind.ExactMatch
|
||||
assert (
|
||||
mod.add_comdat("surface_comdat").selection_kind
|
||||
== llvm.ComdatSelectionKind.ExactMatch
|
||||
)
|
||||
|
||||
opts = llvm.PassBuilderOptions()
|
||||
mod.run_passes("default<O0>", options=opts)
|
||||
|
||||
bitcode = mod.write_bitcode_to_memory_buffer()
|
||||
with llvm.BinaryManager.from_bytes(bitcode) as binary:
|
||||
assert binary.copy_to_memory_buffer()
|
||||
|
||||
target = llvm.Target.from_triple(llvm.default_target_triple)
|
||||
assert target is not None
|
||||
tm = llvm.TargetMachine.create(target, llvm.default_target_triple)
|
||||
td = tm.create_data_layout()
|
||||
assert str(llvm.TargetData.create(str(td))) == str(td)
|
||||
|
||||
dis = llvm.Disasm.create(llvm.default_target_triple)
|
||||
assert hasattr(dis, "is_valid")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_module_add_reuse_existing_semantics()
|
||||
test_named_struct_reuse_existing_semantics()
|
||||
test_member_factories_and_builder_navigation()
|
||||
print("test_api_surface_cleanup: PASSED")
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Regression coverage for GitHub issues 11, 12, and 13."""
|
||||
|
||||
import llvm
|
||||
|
||||
|
||||
def test_issue_11_types_aliases_share_context_type_factory() -> None:
|
||||
with llvm.create_context() as ctx:
|
||||
with ctx.create_module("types_aliases") as mod:
|
||||
i32 = ctx.types.i32
|
||||
fn = mod.add_function("f", ctx.types.function(i32, [i32]))
|
||||
bb = fn.append_basic_block("entry")
|
||||
with bb.create_builder() as b:
|
||||
value = b.add(fn.get_param(0), i32.constant(1), "value")
|
||||
b.ret(value)
|
||||
|
||||
assert ctx.types == mod.types
|
||||
assert ctx.types == fn.types
|
||||
assert ctx.types == bb.types
|
||||
assert ctx.types == value.types
|
||||
assert mod.types.i64 == ctx.types.i64
|
||||
assert fn.types.function(i32, [i32]) == ctx.types.function(i32, [i32])
|
||||
|
||||
|
||||
def test_issue_12_function_create_builder_creates_entry_block() -> None:
|
||||
with llvm.create_context() as ctx:
|
||||
with ctx.create_module("function_create_builder") as mod:
|
||||
i64 = mod.types.i64
|
||||
fn = mod.add_function("lift2", mod.types.function(i64, [i64, i64]))
|
||||
|
||||
with fn.create_builder() as ir:
|
||||
ir.ret(i64.constant(0))
|
||||
|
||||
assert fn.basic_block_count == 1
|
||||
assert fn.entry_block.name == "entry"
|
||||
assert mod.verify(), mod.verification_error
|
||||
assert "define i64 @lift2" in str(mod)
|
||||
assert "ret i64 0" in str(mod)
|
||||
|
||||
|
||||
def test_issue_13_alloca_count_overload_replaces_array_alloca() -> None:
|
||||
with llvm.create_context() as ctx:
|
||||
with ctx.create_module("alloca_count_overload") as mod:
|
||||
void = mod.types.void
|
||||
i32 = mod.types.i32
|
||||
fn = mod.add_function("f", mod.types.function(void, []))
|
||||
|
||||
with fn.create_builder() as b:
|
||||
scalar = b.alloca(i32, "scalar")
|
||||
array = b.alloca(i32, i32.constant(4), "array")
|
||||
b.ret_void()
|
||||
|
||||
assert not hasattr(llvm.Builder, "array_alloca")
|
||||
assert not scalar.is_array_allocation
|
||||
assert array.is_array_allocation
|
||||
ir = str(mod)
|
||||
assert "%scalar = alloca i32" in ir
|
||||
assert "%array = alloca i32, i32 4" in ir
|
||||
assert mod.verify(), mod.verification_error
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_issue_11_types_aliases_share_context_type_factory()
|
||||
test_issue_12_function_create_builder_creates_entry_block()
|
||||
test_issue_13_alloca_count_overload_replaces_array_alloca()
|
||||
print("test_github_issues_11_12_13: PASSED")
|
||||
@@ -12,7 +12,7 @@ def test_alloca_array_size_and_is_array_allocation() -> None:
|
||||
|
||||
with entry.create_builder() as b:
|
||||
scalar = b.alloca(i32, "scalar")
|
||||
array = b.array_alloca(i32, i32.constant(4, False), "array")
|
||||
array = b.alloca(i32, i32.constant(4, False), "array")
|
||||
b.ret_void()
|
||||
|
||||
assert scalar.allocated_type == i32
|
||||
|
||||
@@ -39,7 +39,7 @@ def main():
|
||||
|
||||
# Array alloca (dynamic size)
|
||||
array_size = i32.constant(5)
|
||||
array_alloca = builder.array_alloca(i32, array_size, "dynamic_array")
|
||||
array_alloca = builder.alloca(i32, array_size, "dynamic_array")
|
||||
|
||||
# Static array alloca
|
||||
static_array = builder.alloca(arr_ty, "static_array")
|
||||
|
||||
Reference in New Issue
Block a user