Minor API changes

Closes #11
Closes #12
Closes #13
This commit is contained in:
Duncan Ogilvie
2026-05-13 20:18:43 +02:00
parent e87f64cb0b
commit 44840dc279
7 changed files with 195 additions and 340 deletions
+11
View File
@@ -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.
+2 -3
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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")