test: Cover lexical region lowering

2a67faea10bc90ec2c810c94e06b752a2e30905084878116431fed5bc6668aea
Alexis Sellier committed ago 1 parent 9a8d09d2
Makefile +12 -3
1 1
# Radiance build file.
2 2
3 3
# Core standard library modules.
4 4
STD := -pkg std $(patsubst %,-mod %,$(shell cat std.lib))
5 +
# Session allocation support for standalone lowering fixtures.
6 +
TEST_FIXTURE_STD_LIB := $(shell cat test/support/std.lib)
7 +
TEST_FIXTURE_STD := -pkg std $(patsubst %,-mod %,$(TEST_FIXTURE_STD_LIB))
5 8
6 9
# Full standard library with test modules.
7 10
STD_TEST := $(STD) $(patsubst %,-mod %,$(shell cat std.lib.test))
8 11
9 12
# Source files.
39 42
40 43
SEED      := seed/radiance.rv64
41 44
COMPILER_SRC := compiler/radiance.rad compiler/radiance/codegen.rad
42 45
SEED_OPTS := $(STD) -pkg radiance $(patsubst %,-mod %,$(COMPILER_SRC)) -entry radiance
43 46
44 -
$(RAD_BIN): $(STD_LIB) $(COMPILER_SRC) | $(BIN_DIR)
47 +
$(RAD_BIN): $(STD_LIB) $(COMPILER_SRC) std.lib | $(BIN_DIR)
45 48
	@echo "radiance $(SEED) => $@"
46 49
	@$(EMU) $(EMU_FLAGS) -run $(SEED) $(SEED_OPTS) -o $@
47 50
48 51
$(BIN_DIR):
49 52
	@mkdir -p $@
54 57
55 58
std-test: $(STD_LIB_TEST)
56 59
	@echo
57 60
	@$(EMU) $(EMU_FLAGS) -run $(STD_LIB_TEST)
58 61
59 -
$(STD_LIB_TEST): $(STD_LIB) $(RAD_BIN)
62 +
$(STD_LIB_TEST): $(STD_LIB) $(RAD_BIN) std.lib std.lib.test
60 63
	@echo "radiance -test $(STD_TEST) -entry std -o $@"
61 64
	@$(RADIANCE) -test $(STD_TEST) -entry std -o $@
62 65
63 66
clean-std-test:
64 67
	@rm -f lib/std.test.rv64 \
91 94
92 95
# A `.rad` executable test can have a same-basename `.ras` module.
93 96
$(patsubst %.ras,%.rv64,$(BIN_TEST_RAD_ASM_SRC)): %.rv64: %.ras
94 97
$(patsubst %.start.ras,%.rv64,$(BIN_TEST_RAD_START_SRC)): %.rv64: %.start.ras
95 98
99 +
# Package fixtures can request session support.
100 +
BIN_TEST_SESSION_SRC := $(shell grep -l '^//! session-support$$' $(BIN_TEST_RAD_EXE_SRC))
101 +
$(BIN_TEST_SESSION_SRC:.rad=.rv64): TEST_STD_FLAGS := $(TEST_FIXTURE_STD)
102 +
$(BIN_TEST_SESSION_SRC:.rad=.rv64): TEST_ENTRY_FLAGS := -entry test
103 +
$(BIN_TEST_SESSION_SRC:.rad=.rv64): $(TEST_FIXTURE_STD_LIB) test/support/std.lib
104 +
96 105
# Compile each executable test to a binary.
97 106
$(BIN_TEST_DIR)/%.rv64: $(BIN_TEST_DIR)/%.rad $(RAD_BIN)
98 107
	@echo "radiance $< => $@"
99 -
	@$(RADIANCE) -pkg test -mod $< $(patsubst %,-mod %,$(wildcard $(@:.rv64=)/*.rad)) $(patsubst %,-start %,$(wildcard $(@:.rv64=.start.ras))) $(patsubst %,-mod %,$(wildcard $(@:.rv64=.ras))) -o $@
108 +
	@$(RADIANCE) $(TEST_STD_FLAGS) -pkg test -mod $< $(TEST_ENTRY_FLAGS) $(patsubst %,-mod %,$(wildcard $(@:.rv64=)/*.rad)) $(patsubst %,-start %,$(wildcard $(@:.rv64=.start.ras))) $(patsubst %,-mod %,$(wildcard $(@:.rv64=.ras))) -o $@
100 109
101 110
$(BIN_TEST_DIR)/%.rv64: $(BIN_TEST_DIR)/%.ras $(BIN_RUNNER)
102 111
	@echo "asm $< => $@"
103 112
	@$(EMU) $(EMU_FLAGS) -run $(BIN_RUNNER) -- assemble $< $@
104 113
test/package-golden added +50 -0
1 +
#!/bin/sh
2 +
# Compare one package's emitted IL with its golden file and session support.
3 +
set -eu
4 +
5 +
source=$1
6 +
expected=${source%.rad}.ril
7 +
module=$(basename "${source%.rad}")
8 +
work=$(mktemp -d)
9 +
trap 'rm -rf "$work"' EXIT HUP INT TERM
10 +
11 +
set -- -pkg std
12 +
while IFS= read -r source_module; do
13 +
    set -- "$@" -mod "$source_module"
14 +
done < test/support/std.lib
15 +
set -- "$@" -pkg test -mod "$source" -entry test -dump il
16 +
for source_module in "${source%.rad}"/*.rad; do
17 +
    if [ -f "$source_module" ]; then
18 +
        set -- "$@" -mod "$source_module"
19 +
    fi
20 +
done
21 +
22 +
if ! ${RAD_EMULATOR:-emulator} -memory-size=385024 -data-size=348160 \
23 +
    -stack-size=1024 -run bin/radiance.rv64.dev "$@" >"$work/program.il" 2>"$work/compiler.log"; then
24 +
    cat "$work/compiler.log"
25 +
    cat "$work/program.il"
26 +
    exit 1
27 +
fi
28 +
29 +
# Top-level function and data definitions carry the source module's prefix.
30 +
awk -v prefix="\$\"$module::" '
31 +
    /^(fn |data )/ { keep = index($0, prefix) > 0 }
32 +
    keep { print }
33 +
    /^}/ { if (keep) print ""; keep = 0 }
34 +
' "$work/program.il" >"$work/actual.ril"
35 +
if [ ! -s "$work/actual.ril" ]; then
36 +
    echo "error: no IL definitions found for $module"
37 +
    exit 1
38 +
fi
39 +
40 +
# Golden comparisons ignore comments, indentation, and blank lines.
41 +
for kind in actual expected; do
42 +
    input=$expected
43 +
    if [ "$kind" = actual ]; then input=$work/actual.ril; fi
44 +
    awk '{ sub(/\/\/.*/, ""); gsub(/^[ \t]+|[ \t]+$/, ""); if (length) print }' \
45 +
        "$input" >"$work/$kind.normalized"
46 +
done
47 +
if ! cmp -s "$work/expected.normalized" "$work/actual.normalized"; then
48 +
    diff -u "$expected" "$work/actual.ril" || true
49 +
    exit 1
50 +
fi
test/run +12 -1
6 6
# `test/tests/`.
7 7
#
8 8
# For each test:
9 9
#   - If a `.ril` file exists alongside it, the IL output is checked
10 10
#     against it via the runner binary.
11 +
#   - If `//! session-support` appears, the IL check uses the fixture allocator
12 +
#     package required by session allocation.
11 13
#   - If `//! returns: N` appears in the file, the test is compiled to
12 14
#     a binary and executed; the exit code must match N.
13 15
#   - If `//! rw-data-size: N` appears in the file, the emitted image header's
14 16
#     rwdata size must match N bytes.
15 17
51 53
52 54
  ril="${base}.ril"
53 55
  bin="${base}.rv64"
54 56
  # IL check: run the runner if a .ril file exists.
55 57
  if [ -f "$ril" ]; then
56 -
    if $EMU "$RUNNER" -- "$test"; then
58 +
    if grep -q '^//! session-support$' "$test"; then
59 +
      echo -n "test $test ... "
60 +
      if test/package-golden "$test"; then
61 +
        echo "ok"
62 +
        passed=$((passed + 1))
63 +
      else
64 +
        echo "FAILED"
65 +
        failed=$((failed + 1))
66 +
      fi
67 +
    elif $EMU "$RUNNER" -- "$test"; then
57 68
      passed=$((passed + 1))
58 69
    else
59 70
      failed=$((failed + 1))
60 71
    fi
61 72
  fi
test/support/std.lib added +3 -0
1 +
test/support/std.rad
2 +
test/support/std/lang.rad
3 +
test/support/std/lang/alloc.rad
test/support/std.rad added +3 -0
1 +
//! Minimal standard package root for binary lowering fixtures.
2 +
3 +
export mod lang;
test/support/std/lang.rad added +3 -0
1 +
//! Language support for binary lowering fixtures.
2 +
3 +
export mod alloc;
test/support/std/lang/alloc.rad added +93 -0
1 +
//! Arena allocation support for binary lowering fixtures.
2 +
3 +
/// Error returned when an arena cannot satisfy an allocation.
4 +
export union AllocError: Copy {
5 +
    /// The arena has insufficient storage.
6 +
    OutOfMemory,
7 +
}
8 +
9 +
/// Bump allocator backed by a byte slice.
10 +
export record Arena {
11 +
    /// Backing storage.
12 +
    data: *mut [u8],
13 +
    /// Current allocation offset in bytes.
14 +
    offset: u32,
15 +
}
16 +
17 +
/// Create an arena backed by `data`.
18 +
export fn new(data: *mut [u8]) -> Arena {
19 +
    return Arena { data, offset: 0 };
20 +
}
21 +
22 +
/// Reset the arena to its initial empty state.
23 +
export fn reset(arena: &mut Arena) {
24 +
    set arena.offset = 0;
25 +
}
26 +
27 +
/// Return the number of bytes committed in the arena.
28 +
export fn used(arena: &Arena) -> u32 {
29 +
    return arena.offset;
30 +
}
31 +
32 +
/// Allocate aligned storage without changing the arena after failure.
33 +
export unsafe fn alloc(arena: *unsafe mut Arena, size: u32, alignment: u32) -> *mut opaque throws (AllocError) {
34 +
    assert alignment > 0;
35 +
    assert size > 0;
36 +
    assert (alignment & (alignment - 1)) == 0;
37 +
38 +
    let capacity = arena.data.len;
39 +
    if arena.offset >= capacity {
40 +
        throw AllocError::OutOfMemory;
41 +
    }
42 +
    let address = &arena.data[0] as u64;
43 +
    let mask = (alignment - 1) as u64;
44 +
    let remainder = ((address & mask) + (arena.offset as u64 & mask)) & mask;
45 +
    let padding = ((alignment as u64 - remainder) & mask) as u32;
46 +
    let available = capacity - arena.offset;
47 +
    if padding > available or size > available - padding {
48 +
        throw AllocError::OutOfMemory;
49 +
    }
50 +
    let aligned = arena.offset + padding;
51 +
    let base: *mut u8 = &mut arena.data[aligned];
52 +
    set arena.offset = aligned + size;
53 +
    return base as *mut opaque;
54 +
}
55 +
56 +
/// Allocate raw storage that remains valid until the arena is reset.
57 +
export unsafe fn allocRaw(arena: &mut Arena, size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError) {
58 +
    let owner = try alloc(&mut *arena, size, alignment);
59 +
    let byte = owner as *mut u8;
60 +
    return &mut *byte as *unsafe mut opaque;
61 +
}
62 +
63 +
/// Allocate a raw slice that remains valid until the arena is reset.
64 +
export unsafe fn allocRawSlice(arena: &mut Arena, size: u32, alignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError) {
65 +
    if count == 0 {
66 +
        return &mut [];
67 +
    }
68 +
    if size <> 0 and count > 4294967295 / size {
69 +
        throw AllocError::OutOfMemory;
70 +
    }
71 +
    let raw = try allocRaw(arena, size * count, alignment);
72 +
    return @sliceOf(raw, count);
73 +
}
74 +
75 +
/// Raw storage provider for allocation sessions.
76 +
export trait Alloc {
77 +
    /// Reserve one uninitialized object.
78 +
    unsafe fn (&mut Alloc) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError);
79 +
    /// Reserve an uninitialized slice.
80 +
    unsafe fn (&mut Alloc) reserveSlice(itemSize: u32, itemAlignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError);
81 +
}
82 +
83 +
instance Alloc for Arena {
84 +
    /// Reserve one uninitialized object in the arena.
85 +
    unsafe fn (arena: &mut Arena) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (AllocError) {
86 +
        return try allocRaw(arena, size, alignment);
87 +
    }
88 +
89 +
    /// Reserve an uninitialized slice in the arena.
90 +
    unsafe fn (arena: &mut Arena) reserveSlice(size: u32, alignment: u32, count: u32) -> *unsafe mut [opaque] throws (AllocError) {
91 +
        return try allocRawSlice(arena, size, alignment, count);
92 +
    }
93 +
}
test/tests/binding.storage.rad added +21 -0
1 +
//! returns: 42
2 +
3 +
/// Aggregate whose fields need initialized storage.
4 +
record Pair: Copy {
5 +
    /// First summand.
6 +
    first: u32,
7 +
    /// Second summand.
8 +
    second: u32,
9 +
}
10 +
11 +
@default unsafe fn main() -> u32 {
12 +
    let mut pair: Pair = undefined;
13 +
    set pair.first = 40;
14 +
    set pair.second = 2;
15 +
    let numbers: [u32; 2] = [40, 2];
16 +
    assert pair.first == numbers[0];
17 +
    assert pair.second == numbers[1];
18 +
    let wrapped: ?Pair = pair;
19 +
    let value = wrapped else panic;
20 +
    return value.first + value.second;
21 +
}
test/tests/binding.storage.ril added +43 -0
1 +
fn w32 $main() {
2 +
  @entry0
3 +
    reserve %0 8 4;
4 +
    store w32 40 %0 0;
5 +
    store w32 2 %0 4;
6 +
    reserve %1 8 4;
7 +
    store w32 40 %1 0;
8 +
    store w32 2 %1 4;
9 +
    load w32 %2 %0 0;
10 +
    load w32 %3 %1 0;
11 +
    br.eq w32 %2 %3 @assert.ok2 @assert.fail1;
12 +
  @assert.fail1
13 +
    unreachable;
14 +
  @assert.ok2
15 +
    load w32 %4 %0 4;
16 +
    mul w64 %5 1 4;
17 +
    add w64 %6 %1 %5;
18 +
    load w32 %7 %6 0;
19 +
    br.eq w32 %4 %7 @assert.ok4 @assert.fail3;
20 +
  @assert.fail3
21 +
    unreachable;
22 +
  @assert.ok4
23 +
    reserve %8 12 4;
24 +
    store w8 1 %8 0;
25 +
    add w64 %9 %8 4;
26 +
    blit %9 %0 8;
27 +
    reserve %10 12 4;
28 +
    blit %10 %8 12;
29 +
    reserve %11 12 4;
30 +
    blit %11 %10 12;
31 +
    load w8 %12 %11 0;
32 +
    br.ne w32 %12 0 @success5 @else6;
33 +
  @success5
34 +
    add w64 %13 %11 4;
35 +
    jmp @merge7;
36 +
  @else6
37 +
    unreachable;
38 +
  @merge7
39 +
    load w32 %14 %13 0;
40 +
    load w32 %15 %13 4;
41 +
    add w32 %16 %14 %15;
42 +
    ret %16;
43 +
}
test/tests/data.optional.nil.rad added +31 -0
1 +
//! returns: 42
2 +
3 +
/// Payload with alignment padding inside a tagged optional.
4 +
record Payload: Copy {
5 +
    /// Small prefix.
6 +
    prefix: u8,
7 +
    /// Aligned value.
8 +
    value: u64,
9 +
}
10 +
11 +
/// Initialized nullable pointer table.
12 +
unsafe static POINTERS: [?*u32; 3] = [nil; 3];
13 +
/// Initialized nullable slice.
14 +
unsafe static SLICE: ?*[u8] = nil;
15 +
/// Initialized tagged record optionals.
16 +
unsafe static RECORDS: [?Payload; 2] = [nil, nil];
17 +
/// Initialized nested optional.
18 +
unsafe static NESTED: ??u32 = nil;
19 +
20 +
@default unsafe fn main() -> u32 {
21 +
    for pointer in &POINTERS[..] {
22 +
        assert pointer == nil;
23 +
    }
24 +
    assert SLICE == nil;
25 +
    assert RECORDS[0] == nil;
26 +
    assert RECORDS[1] == nil;
27 +
    assert NESTED == nil;
28 +
    set RECORDS[1] = Payload { prefix: 2, value: 40 };
29 +
    let result = RECORDS[1] else panic;
30 +
    return result.prefix as u32 + result.value as u32;
31 +
}
test/tests/data.optional.nil.ril added +103 -0
1 +
data mut $POINTERS align 8 {
2 +
    w8 0 * 8;
3 +
    w8 0 * 8;
4 +
    w8 0 * 8;
5 +
}
6 +
7 +
data mut $SLICE align 8 {
8 +
    w8 0 * 16;
9 +
}
10 +
11 +
data mut $RECORDS align 8 {
12 +
    w8 0 * 24;
13 +
    w8 0 * 24;
14 +
}
15 +
16 +
data mut $NESTED align 4 {
17 +
    w8 0 * 12;
18 +
}
19 +
20 +
fn w32 $main() {
21 +
  @entry0
22 +
    copy %0 $POINTERS;
23 +
    reserve %1 16 8;
24 +
    store w64 %0 %1 0;
25 +
    store w32 3 %1 8;
26 +
    store w32 3 %1 12;
27 +
    load w32 %2 %1 8;
28 +
    load w64 %3 %1 0;
29 +
    jmp @loop1(0);
30 +
  @loop1(w32 %4)
31 +
    br.slt w32 %4 %2 @body2 @merge3;
32 +
  @body2
33 +
    mul w64 %5 %4 8;
34 +
    add w64 %6 %3 %5;
35 +
    load w64 %7 %6 0;
36 +
    br.eq w64 %7 0 @assert.ok5 @assert.fail4;
37 +
  @merge3
38 +
    copy %9 $SLICE;
39 +
    load w64 %10 %9 0;
40 +
    eq w64 %11 %10 0;
41 +
    br.ne w32 %11 0 @assert.ok7 @assert.fail6;
42 +
  @assert.fail4
43 +
    unreachable;
44 +
  @assert.ok5
45 +
    add w32 %8 %4 1;
46 +
    jmp @loop1(%8);
47 +
  @assert.fail6
48 +
    unreachable;
49 +
  @assert.ok7
50 +
    copy %12 $RECORDS;
51 +
    load w8 %13 %12 0;
52 +
    eq w8 %14 %13 0;
53 +
    br.ne w32 %14 0 @assert.ok9 @assert.fail8;
54 +
  @assert.fail8
55 +
    unreachable;
56 +
  @assert.ok9
57 +
    copy %15 $RECORDS;
58 +
    mul w64 %16 1 24;
59 +
    add w64 %17 %15 %16;
60 +
    load w8 %18 %17 0;
61 +
    eq w8 %19 %18 0;
62 +
    br.ne w32 %19 0 @assert.ok11 @assert.fail10;
63 +
  @assert.fail10
64 +
    unreachable;
65 +
  @assert.ok11
66 +
    copy %20 $NESTED;
67 +
    load w8 %21 %20 0;
68 +
    eq w8 %22 %21 0;
69 +
    br.ne w32 %22 0 @assert.ok13 @assert.fail12;
70 +
  @assert.fail12
71 +
    unreachable;
72 +
  @assert.ok13
73 +
    reserve %23 16 8;
74 +
    store w8 2 %23 0;
75 +
    store w64 40 %23 8;
76 +
    reserve %24 24 8;
77 +
    store w8 1 %24 0;
78 +
    add w64 %25 %24 8;
79 +
    blit %25 %23 16;
80 +
    copy %26 $RECORDS;
81 +
    mul w64 %27 1 24;
82 +
    add w64 %28 %26 %27;
83 +
    blit %28 %24 24;
84 +
    copy %29 $RECORDS;
85 +
    mul w64 %30 1 24;
86 +
    add w64 %31 %29 %30;
87 +
    reserve %32 24 8;
88 +
    blit %32 %31 24;
89 +
    load w8 %33 %32 0;
90 +
    br.ne w32 %33 0 @success14 @else15;
91 +
  @success14
92 +
    add w64 %34 %32 8;
93 +
    jmp @merge16;
94 +
  @else15
95 +
    unreachable;
96 +
  @merge16
97 +
    load w8 %35 %34 0;
98 +
    zext w8 %36 %35;
99 +
    load w64 %37 %34 8;
100 +
    zext w32 %38 %37;
101 +
    add w32 %39 %36 %38;
102 +
    ret %39;
103 +
}
test/tests/data.optional.value.rad added +63 -0
1 +
//! returns: 42
2 +
3 +
/// Aligned record payload in a present optional.
4 +
record Payload: Copy {
5 +
    /// Small prefix before the aligned value.
6 +
    prefix: u8,
7 +
    /// Value used to check payload alignment.
8 +
    number: u64,
9 +
}
10 +
11 +
/// Tagged payload with both empty and initialized variants.
12 +
union Value: Copy { Empty, Number(i64), Pair { left: u8, right: u64 } }
13 +
14 +
/// Optional payload in a tagged instruction.
15 +
union Instruction: Copy { Return { value: ?Value } }
16 +
17 +
/// Optional constant reused as a nested optional payload.
18 +
constant PRESENT: ?u32 = 42;
19 +
/// Absent inner payload used in a present outer optional.
20 +
constant ABSENT: ?u32 = nil;
21 +
/// Present aligned record initializer.
22 +
unsafe static RECORD: ?Payload = Payload { prefix: 2, number: 40 };
23 +
/// Present outer optional that contains a present value.
24 +
unsafe static NESTED: ??u32 = PRESENT;
25 +
/// Present outer optional that contains an absent value.
26 +
unsafe static NESTED_NIL: ??u32 = ABSENT;
27 +
/// Repeated present optional values.
28 +
unsafe static REPEATED: [?u32; 2] = [PRESENT; 2];
29 +
/// Present nullable slice initializer.
30 +
unsafe static TEXT: ?*[u8] = "answer";
31 +
32 +
@default unsafe fn main() -> u32 {
33 +
    let instructions = &[
34 +
        Instruction::Return { value: Value::Number(42) },
35 +
        Instruction::Return { value: Value::Pair { left: 2, right: 40 } },
36 +
        Instruction::Return { value: Value::Empty }
37 +
    ];
38 +
    let case Instruction::Return { value } = instructions[0] else panic;
39 +
    let present = value else panic;
40 +
    let case Value::Number(number) = present else panic;
41 +
    assert number == 42;
42 +
    let case Instruction::Return { value: second } = instructions[1] else panic;
43 +
    let pair = second else panic;
44 +
    let case Value::Pair { left, right } = pair else panic;
45 +
    assert left as u64 + right == 42;
46 +
    let case Instruction::Return { value: third } = instructions[2] else panic;
47 +
    let empty = third else panic;
48 +
    let case Value::Empty = empty else panic;
49 +
    let rec = RECORD else panic;
50 +
    assert rec.prefix as u64 + rec.number == 42;
51 +
    let inner = NESTED else panic;
52 +
    let answer = inner else panic;
53 +
    assert answer == 42;
54 +
    let missing = NESTED_NIL else panic;
55 +
    assert missing == nil;
56 +
    for item in &REPEATED[..] {
57 +
        let value = item else panic;
58 +
        assert value == 42;
59 +
    }
60 +
    let text = TEXT else panic;
61 +
    assert text.len == 6;
62 +
    return number as u32;
63 +
}
test/tests/data.optional.value.ril added +320 -0
1 +
data $PRESENT align 4 {
2 +
    w8 1;
3 +
    undef * 3;
4 +
    w32 42;
5 +
}
6 +
7 +
data $ABSENT align 4 {
8 +
    w8 0 * 8;
9 +
}
10 +
11 +
data mut $RECORD align 8 {
12 +
    w8 1;
13 +
    undef * 7;
14 +
    w8 2;
15 +
    undef * 7;
16 +
    w64 40;
17 +
}
18 +
19 +
data mut $NESTED align 4 {
20 +
    w8 1;
21 +
    undef * 3;
22 +
    w8 1;
23 +
    undef * 3;
24 +
    w32 42;
25 +
}
26 +
27 +
data mut $NESTED_NIL align 4 {
28 +
    w8 1;
29 +
    undef * 3;
30 +
    w8 0 * 8;
31 +
}
32 +
33 +
data mut $REPEATED align 4 {
34 +
    w8 1;
35 +
    undef * 3;
36 +
    w32 42;
37 +
    w8 1;
38 +
    undef * 3;
39 +
    w32 42;
40 +
}
41 +
42 +
data $TEXT$literal$6 align 1 {
43 +
    str "answer";
44 +
}
45 +
46 +
data mut $TEXT align 8 {
47 +
    sym $TEXT$literal$6;
48 +
    w32 6;
49 +
    w32 6;
50 +
}
51 +
52 +
data $main$literal$0 align 8 {
53 +
    w8 0;
54 +
    undef * 7;
55 +
    w8 1;
56 +
    undef * 7;
57 +
    w8 1;
58 +
    undef * 7;
59 +
    w64 42;
60 +
    undef * 8;
61 +
    w8 0;
62 +
    undef * 7;
63 +
    w8 1;
64 +
    undef * 7;
65 +
    w8 2;
66 +
    undef * 7;
67 +
    w8 2;
68 +
    undef * 7;
69 +
    w64 40;
70 +
    w8 0;
71 +
    undef * 7;
72 +
    w8 1;
73 +
    undef * 7;
74 +
    w8 0;
75 +
    undef * 7;
76 +
    undef * 16;
77 +
}
78 +
79 +
fn w32 $main() {
80 +
  @entry0
81 +
    copy %0 $main$literal$0;
82 +
    reserve %1 16 8;
83 +
    store w64 %0 %1 0;
84 +
    store w32 3 %1 8;
85 +
    store w32 3 %1 12;
86 +
    load w32 %2 %1 8;
87 +
    br.ult w32 0 %2 @guard#pass1 @guard#trap2;
88 +
  @guard#pass1
89 +
    load w64 %3 %1 0;
90 +
    reserve %4 40 8;
91 +
    blit %4 %3 40;
92 +
    load w8 %5 %4 0;
93 +
    br.eq w8 %5 0 @success3 @else4;
94 +
  @guard#trap2
95 +
    ebreak;
96 +
    unreachable;
97 +
  @success3
98 +
    add w64 %6 %4 8;
99 +
    jmp @merge5;
100 +
  @else4
101 +
    unreachable;
102 +
  @merge5
103 +
    reserve %7 32 8;
104 +
    blit %7 %6 32;
105 +
    load w8 %8 %7 0;
106 +
    br.ne w32 %8 0 @success6 @else7;
107 +
  @success6
108 +
    add w64 %9 %7 8;
109 +
    jmp @merge8;
110 +
  @else7
111 +
    unreachable;
112 +
  @merge8
113 +
    reserve %10 24 8;
114 +
    blit %10 %9 24;
115 +
    load w8 %11 %10 0;
116 +
    br.eq w8 %11 1 @success9 @else10;
117 +
  @success9
118 +
    sload w64 %12 %10 8;
119 +
    jmp @merge11;
120 +
  @else10
121 +
    unreachable;
122 +
  @merge11
123 +
    br.eq w64 %12 42 @assert.ok13 @assert.fail12;
124 +
  @assert.fail12
125 +
    unreachable;
126 +
  @assert.ok13
127 +
    load w32 %13 %1 8;
128 +
    br.ult w32 1 %13 @guard#pass14 @guard#trap15;
129 +
  @guard#pass14
130 +
    load w64 %14 %1 0;
131 +
    mul w64 %15 1 40;
132 +
    add w64 %16 %14 %15;
133 +
    reserve %17 40 8;
134 +
    blit %17 %16 40;
135 +
    load w8 %18 %17 0;
136 +
    br.eq w8 %18 0 @success16 @else17;
137 +
  @guard#trap15
138 +
    ebreak;
139 +
    unreachable;
140 +
  @success16
141 +
    add w64 %19 %17 8;
142 +
    jmp @merge18;
143 +
  @else17
144 +
    unreachable;
145 +
  @merge18
146 +
    reserve %20 32 8;
147 +
    blit %20 %19 32;
148 +
    load w8 %21 %20 0;
149 +
    br.ne w32 %21 0 @success19 @else20;
150 +
  @success19
151 +
    add w64 %22 %20 8;
152 +
    jmp @merge21;
153 +
  @else20
154 +
    unreachable;
155 +
  @merge21
156 +
    reserve %23 24 8;
157 +
    blit %23 %22 24;
158 +
    load w8 %24 %23 0;
159 +
    br.eq w8 %24 2 @success22 @else23;
160 +
  @success22
161 +
    add w64 %25 %23 8;
162 +
    load w8 %26 %25 0;
163 +
    load w64 %27 %25 8;
164 +
    jmp @merge24;
165 +
  @else23
166 +
    unreachable;
167 +
  @merge24
168 +
    zext w8 %28 %26;
169 +
    add w64 %29 %28 %27;
170 +
    br.eq w64 %29 42 @assert.ok26 @assert.fail25;
171 +
  @assert.fail25
172 +
    unreachable;
173 +
  @assert.ok26
174 +
    load w32 %30 %1 8;
175 +
    br.ult w32 2 %30 @guard#pass27 @guard#trap28;
176 +
  @guard#pass27
177 +
    load w64 %31 %1 0;
178 +
    mul w64 %32 2 40;
179 +
    add w64 %33 %31 %32;
180 +
    reserve %34 40 8;
181 +
    blit %34 %33 40;
182 +
    load w8 %35 %34 0;
183 +
    br.eq w8 %35 0 @success29 @else30;
184 +
  @guard#trap28
185 +
    ebreak;
186 +
    unreachable;
187 +
  @success29
188 +
    add w64 %36 %34 8;
189 +
    jmp @merge31;
190 +
  @else30
191 +
    unreachable;
192 +
  @merge31
193 +
    reserve %37 32 8;
194 +
    blit %37 %36 32;
195 +
    load w8 %38 %37 0;
196 +
    br.ne w32 %38 0 @success32 @else33;
197 +
  @success32
198 +
    add w64 %39 %37 8;
199 +
    jmp @merge34;
200 +
  @else33
201 +
    unreachable;
202 +
  @merge34
203 +
    reserve %40 24 8;
204 +
    blit %40 %39 24;
205 +
    load w8 %41 %40 0;
206 +
    br.eq w8 %41 0 @success35 @else36;
207 +
  @success35
208 +
    jmp @merge37;
209 +
  @else36
210 +
    unreachable;
211 +
  @merge37
212 +
    copy %42 $RECORD;
213 +
    reserve %43 24 8;
214 +
    blit %43 %42 24;
215 +
    load w8 %44 %43 0;
216 +
    br.ne w32 %44 0 @success38 @else39;
217 +
  @success38
218 +
    add w64 %45 %43 8;
219 +
    jmp @merge40;
220 +
  @else39
221 +
    unreachable;
222 +
  @merge40
223 +
    load w8 %46 %45 0;
224 +
    zext w8 %47 %46;
225 +
    load w64 %48 %45 8;
226 +
    add w64 %49 %47 %48;
227 +
    br.eq w64 %49 42 @assert.ok42 @assert.fail41;
228 +
  @assert.fail41
229 +
    unreachable;
230 +
  @assert.ok42
231 +
    copy %50 $NESTED;
232 +
    reserve %51 12 4;
233 +
    blit %51 %50 12;
234 +
    load w8 %52 %51 0;
235 +
    br.ne w32 %52 0 @success43 @else44;
236 +
  @success43
237 +
    add w64 %53 %51 4;
238 +
    jmp @merge45;
239 +
  @else44
240 +
    unreachable;
241 +
  @merge45
242 +
    reserve %54 8 4;
243 +
    blit %54 %53 8;
244 +
    load w8 %55 %54 0;
245 +
    br.ne w32 %55 0 @success46 @else47;
246 +
  @success46
247 +
    load w32 %56 %54 4;
248 +
    jmp @merge48;
249 +
  @else47
250 +
    unreachable;
251 +
  @merge48
252 +
    br.eq w32 %56 42 @assert.ok50 @assert.fail49;
253 +
  @assert.fail49
254 +
    unreachable;
255 +
  @assert.ok50
256 +
    copy %57 $NESTED_NIL;
257 +
    reserve %58 12 4;
258 +
    blit %58 %57 12;
259 +
    load w8 %59 %58 0;
260 +
    br.ne w32 %59 0 @success51 @else52;
261 +
  @success51
262 +
    add w64 %60 %58 4;
263 +
    jmp @merge53;
264 +
  @else52
265 +
    unreachable;
266 +
  @merge53
267 +
    load w8 %61 %60 0;
268 +
    eq w8 %62 %61 0;
269 +
    br.ne w32 %62 0 @assert.ok55 @assert.fail54;
270 +
  @assert.fail54
271 +
    unreachable;
272 +
  @assert.ok55
273 +
    copy %63 $REPEATED;
274 +
    reserve %64 16 8;
275 +
    store w64 %63 %64 0;
276 +
    store w32 2 %64 8;
277 +
    store w32 2 %64 12;
278 +
    load w32 %65 %64 8;
279 +
    load w64 %66 %64 0;
280 +
    jmp @loop56(0);
281 +
  @loop56(w32 %67)
282 +
    br.slt w32 %67 %65 @body57 @merge58;
283 +
  @body57
284 +
    mul w64 %68 %67 8;
285 +
    add w64 %69 %66 %68;
286 +
    reserve %70 8 4;
287 +
    blit %70 %69 8;
288 +
    load w8 %71 %70 0;
289 +
    br.ne w32 %71 0 @success59 @else60;
290 +
  @merge58
291 +
    copy %74 $TEXT;
292 +
    reserve %75 16 8;
293 +
    blit %75 %74 16;
294 +
    load w64 %76 %75 0;
295 +
    br.ne w32 %76 0 @success64 @else65;
296 +
  @success59
297 +
    load w32 %72 %70 4;
298 +
    jmp @merge61;
299 +
  @else60
300 +
    unreachable;
301 +
  @merge61
302 +
    br.eq w32 %72 42 @assert.ok63 @assert.fail62;
303 +
  @assert.fail62
304 +
    unreachable;
305 +
  @assert.ok63
306 +
    add w32 %73 %67 1;
307 +
    jmp @loop56(%73);
308 +
  @success64
309 +
    jmp @merge66;
310 +
  @else65
311 +
    unreachable;
312 +
  @merge66
313 +
    load w32 %77 %75 8;
314 +
    br.eq w32 %77 6 @assert.ok68 @assert.fail67;
315 +
  @assert.fail67
316 +
    unreachable;
317 +
  @assert.ok68
318 +
    zext w32 %79 %12;
319 +
    ret %79;
320 +
}
test/tests/lowering.scratch.context.rad added +122 -0
1 +
//! returns: 42
2 +
3 +
/// Exercise all sixteen loop slots and their delayed continue targets.
4 +
fn nestedTargets() -> i32 {
5 +
    let mut total: i32 = 0;
6 +
    for index0 in 0..3 {
7 +
        if index0 == 0 {
8 +
            continue;
9 +
        }
10 +
        for index1 in 0..3 {
11 +
            if index1 == 0 {
12 +
                continue;
13 +
            }
14 +
            for index2 in 0..3 {
15 +
                if index2 == 0 {
16 +
                    continue;
17 +
                }
18 +
                for index3 in 0..3 {
19 +
                    if index3 == 0 {
20 +
                        continue;
21 +
                    }
22 +
                    for index4 in 0..3 {
23 +
                        if index4 == 0 {
24 +
                            continue;
25 +
                        }
26 +
                        for index5 in 0..3 {
27 +
                            if index5 == 0 {
28 +
                                continue;
29 +
                            }
30 +
                            for index6 in 0..3 {
31 +
                                if index6 == 0 {
32 +
                                    continue;
33 +
                                }
34 +
                                for index7 in 0..3 {
35 +
                                    if index7 == 0 {
36 +
                                        continue;
37 +
                                    }
38 +
                                    for index8 in 0..3 {
39 +
                                        if index8 == 0 {
40 +
                                            continue;
41 +
                                        }
42 +
                                        for index9 in 0..3 {
43 +
                                            if index9 == 0 {
44 +
                                                continue;
45 +
                                            }
46 +
                                            for index10 in 0..3 {
47 +
                                                if index10 == 0 {
48 +
                                                    continue;
49 +
                                                }
50 +
                                                for index11 in 0..3 {
51 +
                                                    if index11 == 0 {
52 +
                                                        continue;
53 +
                                                    }
54 +
                                                    for index12 in 0..3 {
55 +
                                                        if index12 == 0 {
56 +
                                                            continue;
57 +
                                                        }
58 +
                                                        for index13 in 0..3 {
59 +
                                                            if index13 == 0 {
60 +
                                                                continue;
61 +
                                                            }
62 +
                                                            for index14 in 0..3 {
63 +
                                                                if index14 == 0 {
64 +
                                                                    continue;
65 +
                                                                }
66 +
                                                                for index15 in 0..3 {
67 +
                                                                    if index15 == 0 {
68 +
                                                                        continue;
69 +
                                                                    }
70 +
                                                                    set total += 42;
71 +
                                                                    break;
72 +
                                                                }
73 +
                                                                break;
74 +
                                                            }
75 +
                                                            break;
76 +
                                                        }
77 +
                                                        break;
78 +
                                                    }
79 +
                                                    break;
80 +
                                                }
81 +
                                                break;
82 +
                                            }
83 +
                                            break;
84 +
                                        }
85 +
                                        break;
86 +
                                    }
87 +
                                    break;
88 +
                                }
89 +
                                break;
90 +
                            }
91 +
                            break;
92 +
                        }
93 +
                        break;
94 +
                    }
95 +
                    break;
96 +
                }
97 +
                break;
98 +
            }
99 +
            break;
100 +
        }
101 +
        break;
102 +
    }
103 +
    return total;
104 +
}
105 +
106 +
/// Use all eight source-parameter bindings.
107 +
fn parameters(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) -> i32 {
108 +
    return a + b + c + d + e + f + g + h;
109 +
}
110 +
111 +
/// Bind seven source parameters beside the hidden aggregate-return parameter.
112 +
fn aggregate(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32) -> [i32; 2] {
113 +
    return [a + b + c + d + e + f + g, 42];
114 +
}
115 +
116 +
@default fn main() -> i32 {
117 +
    assert parameters(1, 2, 3, 4, 5, 6, 7, 14) == 42;
118 +
    let pair = aggregate(1, 2, 3, 4, 5, 6, 21);
119 +
    assert pair[0] == 42;
120 +
    assert pair[1] == 42;
121 +
    return nestedTargets();
122 +
}
test/tests/lowering.scratch.context.ril added +265 -0
1 +
fn w32 $nestedTargets() {
2 +
  @entry0
3 +
    jmp @loop1(0, 0);
4 +
  @loop1(w64 %0, w32 %47)
5 +
    br.slt w64 %0 3 @body2 @merge3(%47);
6 +
  @body2
7 +
    br.eq w64 %0 0 @then4 @merge5;
8 +
  @merge3(w32 %49)
9 +
    ret %49;
10 +
  @then4
11 +
    jmp @step6;
12 +
  @merge5
13 +
    jmp @loop7(0, %47);
14 +
  @step6
15 +
    add w64 %48 %0 1;
16 +
    jmp @loop1(%48, %47);
17 +
  @loop7(w64 %1, w32 %45)
18 +
    br.slt w64 %1 3 @body8 @merge9(%45);
19 +
  @body8
20 +
    br.eq w64 %1 0 @then10 @merge11;
21 +
  @merge9(w32 %50)
22 +
    jmp @merge3(%50);
23 +
  @then10
24 +
    jmp @step12;
25 +
  @merge11
26 +
    jmp @loop13(0, %45);
27 +
  @step12
28 +
    add w64 %46 %1 1;
29 +
    jmp @loop7(%46, %45);
30 +
  @loop13(w64 %2, w32 %43)
31 +
    br.slt w64 %2 3 @body14 @merge15(%43);
32 +
  @body14
33 +
    br.eq w64 %2 0 @then16 @merge17;
34 +
  @merge15(w32 %51)
35 +
    jmp @merge9(%51);
36 +
  @then16
37 +
    jmp @step18;
38 +
  @merge17
39 +
    jmp @loop19(0, %43);
40 +
  @step18
41 +
    add w64 %44 %2 1;
42 +
    jmp @loop13(%44, %43);
43 +
  @loop19(w64 %3, w32 %41)
44 +
    br.slt w64 %3 3 @body20 @merge21(%41);
45 +
  @body20
46 +
    br.eq w64 %3 0 @then22 @merge23;
47 +
  @merge21(w32 %52)
48 +
    jmp @merge15(%52);
49 +
  @then22
50 +
    jmp @step24;
51 +
  @merge23
52 +
    jmp @loop25(0, %41);
53 +
  @step24
54 +
    add w64 %42 %3 1;
55 +
    jmp @loop19(%42, %41);
56 +
  @loop25(w64 %4, w32 %39)
57 +
    br.slt w64 %4 3 @body26 @merge27(%39);
58 +
  @body26
59 +
    br.eq w64 %4 0 @then28 @merge29;
60 +
  @merge27(w32 %53)
61 +
    jmp @merge21(%53);
62 +
  @then28
63 +
    jmp @step30;
64 +
  @merge29
65 +
    jmp @loop31(0, %39);
66 +
  @step30
67 +
    add w64 %40 %4 1;
68 +
    jmp @loop25(%40, %39);
69 +
  @loop31(w64 %5, w32 %37)
70 +
    br.slt w64 %5 3 @body32 @merge33(%37);
71 +
  @body32
72 +
    br.eq w64 %5 0 @then34 @merge35;
73 +
  @merge33(w32 %54)
74 +
    jmp @merge27(%54);
75 +
  @then34
76 +
    jmp @step36;
77 +
  @merge35
78 +
    jmp @loop37(0, %37);
79 +
  @step36
80 +
    add w64 %38 %5 1;
81 +
    jmp @loop31(%38, %37);
82 +
  @loop37(w64 %6, w32 %35)
83 +
    br.slt w64 %6 3 @body38 @merge39(%35);
84 +
  @body38
85 +
    br.eq w64 %6 0 @then40 @merge41;
86 +
  @merge39(w32 %55)
87 +
    jmp @merge33(%55);
88 +
  @then40
89 +
    jmp @step42;
90 +
  @merge41
91 +
    jmp @loop43(0, %35);
92 +
  @step42
93 +
    add w64 %36 %6 1;
94 +
    jmp @loop37(%36, %35);
95 +
  @loop43(w64 %7, w32 %33)
96 +
    br.slt w64 %7 3 @body44 @merge45(%33);
97 +
  @body44
98 +
    br.eq w64 %7 0 @then46 @merge47;
99 +
  @merge45(w32 %56)
100 +
    jmp @merge39(%56);
101 +
  @then46
102 +
    jmp @step48;
103 +
  @merge47
104 +
    jmp @loop49(0, %33);
105 +
  @step48
106 +
    add w64 %34 %7 1;
107 +
    jmp @loop43(%34, %33);
108 +
  @loop49(w64 %8, w32 %31)
109 +
    br.slt w64 %8 3 @body50 @merge51(%31);
110 +
  @body50
111 +
    br.eq w64 %8 0 @then52 @merge53;
112 +
  @merge51(w32 %57)
113 +
    jmp @merge45(%57);
114 +
  @then52
115 +
    jmp @step54;
116 +
  @merge53
117 +
    jmp @loop55(0, %31);
118 +
  @step54
119 +
    add w64 %32 %8 1;
120 +
    jmp @loop49(%32, %31);
121 +
  @loop55(w64 %9, w32 %29)
122 +
    br.slt w64 %9 3 @body56 @merge57(%29);
123 +
  @body56
124 +
    br.eq w64 %9 0 @then58 @merge59;
125 +
  @merge57(w32 %58)
126 +
    jmp @merge51(%58);
127 +
  @then58
128 +
    jmp @step60;
129 +
  @merge59
130 +
    jmp @loop61(0, %29);
131 +
  @step60
132 +
    add w64 %30 %9 1;
133 +
    jmp @loop55(%30, %29);
134 +
  @loop61(w64 %10, w32 %27)
135 +
    br.slt w64 %10 3 @body62 @merge63(%27);
136 +
  @body62
137 +
    br.eq w64 %10 0 @then64 @merge65;
138 +
  @merge63(w32 %59)
139 +
    jmp @merge57(%59);
140 +
  @then64
141 +
    jmp @step66;
142 +
  @merge65
143 +
    jmp @loop67(0, %27);
144 +
  @step66
145 +
    add w64 %28 %10 1;
146 +
    jmp @loop61(%28, %27);
147 +
  @loop67(w64 %11, w32 %25)
148 +
    br.slt w64 %11 3 @body68 @merge69(%25);
149 +
  @body68
150 +
    br.eq w64 %11 0 @then70 @merge71;
151 +
  @merge69(w32 %60)
152 +
    jmp @merge63(%60);
153 +
  @then70
154 +
    jmp @step72;
155 +
  @merge71
156 +
    jmp @loop73(0, %25);
157 +
  @step72
158 +
    add w64 %26 %11 1;
159 +
    jmp @loop67(%26, %25);
160 +
  @loop73(w64 %12, w32 %23)
161 +
    br.slt w64 %12 3 @body74 @merge75(%23);
162 +
  @body74
163 +
    br.eq w64 %12 0 @then76 @merge77;
164 +
  @merge75(w32 %61)
165 +
    jmp @merge69(%61);
166 +
  @then76
167 +
    jmp @step78;
168 +
  @merge77
169 +
    jmp @loop79(0, %23);
170 +
  @step78
171 +
    add w64 %24 %12 1;
172 +
    jmp @loop73(%24, %23);
173 +
  @loop79(w64 %13, w32 %21)
174 +
    br.slt w64 %13 3 @body80 @merge81(%21);
175 +
  @body80
176 +
    br.eq w64 %13 0 @then82 @merge83;
177 +
  @merge81(w32 %62)
178 +
    jmp @merge75(%62);
179 +
  @then82
180 +
    jmp @step84;
181 +
  @merge83
182 +
    jmp @loop85(0, %21);
183 +
  @step84
184 +
    add w64 %22 %13 1;
185 +
    jmp @loop79(%22, %21);
186 +
  @loop85(w64 %14, w32 %19)
187 +
    br.slt w64 %14 3 @body86 @merge87(%19);
188 +
  @body86
189 +
    br.eq w64 %14 0 @then88 @merge89;
190 +
  @merge87(w32 %63)
191 +
    jmp @merge81(%63);
192 +
  @then88
193 +
    jmp @step90;
194 +
  @merge89
195 +
    jmp @loop91(0, %19);
196 +
  @step90
197 +
    add w64 %20 %14 1;
198 +
    jmp @loop85(%20, %19);
199 +
  @loop91(w64 %15, w32 %16)
200 +
    br.slt w64 %15 3 @body92 @merge93(%16);
201 +
  @body92
202 +
    br.eq w64 %15 0 @then94 @merge95;
203 +
  @merge93(w32 %64)
204 +
    jmp @merge87(%64);
205 +
  @then94
206 +
    jmp @step96;
207 +
  @merge95
208 +
    add w32 %17 %16 42;
209 +
    jmp @merge93(%17);
210 +
  @step96
211 +
    add w64 %18 %15 1;
212 +
    jmp @loop91(%18, %16);
213 +
}
214 +
215 +
fn w32 $parameters(w32 %0, w32 %1, w32 %2, w32 %3, w32 %4, w32 %5, w32 %6, w32 %7) {
216 +
  @entry0
217 +
    add w32 %8 %0 %1;
218 +
    add w32 %9 %8 %2;
219 +
    add w32 %10 %9 %3;
220 +
    add w32 %11 %10 %4;
221 +
    add w32 %12 %11 %5;
222 +
    add w32 %13 %12 %6;
223 +
    add w32 %14 %13 %7;
224 +
    ret %14;
225 +
}
226 +
227 +
fn w64 $aggregate(w64 %0, w32 %1, w32 %2, w32 %3, w32 %4, w32 %5, w32 %6, w32 %7) {
228 +
  @entry0
229 +
    reserve %8 8 4;
230 +
    add w32 %9 %1 %2;
231 +
    add w32 %10 %9 %3;
232 +
    add w32 %11 %10 %4;
233 +
    add w32 %12 %11 %5;
234 +
    add w32 %13 %12 %6;
235 +
    add w32 %14 %13 %7;
236 +
    store w32 %14 %8 0;
237 +
    store w32 42 %8 4;
238 +
    blit %0 %8 8;
239 +
    ret %0;
240 +
}
241 +
242 +
fn w32 $main() {
243 +
  @entry0
244 +
    call w32 %0 $parameters(1, 2, 3, 4, 5, 6, 7, 14);
245 +
    br.eq w32 %0 42 @assert.ok2 @assert.fail1;
246 +
  @assert.fail1
247 +
    unreachable;
248 +
  @assert.ok2
249 +
    reserve %1 8 4;
250 +
    call w64 %2 $aggregate(%1, 1, 2, 3, 4, 5, 6, 21);
251 +
    sload w32 %3 %2 0;
252 +
    br.eq w32 %3 42 @assert.ok4 @assert.fail3;
253 +
  @assert.fail3
254 +
    unreachable;
255 +
  @assert.ok4
256 +
    mul w64 %4 1 4;
257 +
    add w64 %5 %2 %4;
258 +
    sload w32 %6 %5 0;
259 +
    br.eq w32 %6 42 @assert.ok6 @assert.fail5;
260 +
  @assert.fail5
261 +
    unreachable;
262 +
  @assert.ok6
263 +
    call w32 %7 $nestedTargets();
264 +
    ret %7;
265 +
}
test/tests/match.pointer.bindings.rad added +32 -0
1 +
//! returns: 42
2 +
3 +
record Item: Copy { value: u32 }
4 +
5 +
@default fn main() -> u32 {
6 +
    let mut item = Item { value: 0 };
7 +
    match &mut item {
8 +
        case Item { value } => {
9 +
            set *value = 21;
10 +
        },
11 +
        else => panic,
12 +
    }
13 +
    assert item.value == 21;
14 +
15 +
    let mut values: [u32; 2] = [10, 11];
16 +
    match &mut values {
17 +
        case [first, second] => {
18 +
            set *first += 1;
19 +
            set *second += 1;
20 +
        },
21 +
    }
22 +
    assert values[0] == 11;
23 +
    assert values[1] == 12;
24 +
25 +
    let mut result: u32 = 0;
26 +
    match &mut result {
27 +
        value => {
28 +
            set *value = item.value + values[0] + values[1] - 2;
29 +
        },
30 +
    }
31 +
    return result;
32 +
}
test/tests/match.pointer.bindings.ril added +68 -0
1 +
fn w32 $main() {
2 +
  @entry0
3 +
    reserve %0 4 4;
4 +
    store w32 0 %0 0;
5 +
    jmp @arm1;
6 +
  @arm1
7 +
    jmp @case2;
8 +
  @case2
9 +
    store w32 21 %0 0;
10 +
    jmp @merge4;
11 +
  @arm3
12 +
    jmp @else5;
13 +
  @merge4
14 +
    load w32 %1 %0 0;
15 +
    br.eq w32 %1 21 @assert.ok8 @assert.fail7;
16 +
  @else5
17 +
    unreachable;
18 +
  @assert.fail7
19 +
    unreachable;
20 +
  @assert.ok8
21 +
    reserve %2 8 4;
22 +
    store w32 10 %2 0;
23 +
    store w32 11 %2 4;
24 +
    jmp @arm9;
25 +
  @arm9
26 +
    jmp @case10;
27 +
  @case10
28 +
    add w64 %3 %2 4;
29 +
    load w32 %4 %2 0;
30 +
    add w32 %5 %4 1;
31 +
    store w32 %5 %2 0;
32 +
    load w32 %6 %3 0;
33 +
    add w32 %7 %6 1;
34 +
    store w32 %7 %3 0;
35 +
    jmp @merge12;
36 +
  @merge12
37 +
    load w32 %8 %2 0;
38 +
    br.eq w32 %8 11 @assert.ok14 @assert.fail13;
39 +
  @assert.fail13
40 +
    unreachable;
41 +
  @assert.ok14
42 +
    mul w64 %9 1 4;
43 +
    add w64 %10 %2 %9;
44 +
    load w32 %11 %10 0;
45 +
    br.eq w32 %11 12 @assert.ok16 @assert.fail15;
46 +
  @assert.fail15
47 +
    unreachable;
48 +
  @assert.ok16
49 +
    reserve %12 4 4;
50 +
    store w32 0 %12 0;
51 +
    jmp @arm17;
52 +
  @arm17
53 +
    jmp @case18;
54 +
  @case18
55 +
    load w32 %13 %0 0;
56 +
    load w32 %14 %2 0;
57 +
    add w32 %15 %13 %14;
58 +
    mul w64 %16 1 4;
59 +
    add w64 %17 %2 %16;
60 +
    load w32 %18 %17 0;
61 +
    add w32 %19 %15 %18;
62 +
    sub w32 %20 %19 2;
63 +
    store w32 %20 %12 0;
64 +
    jmp @merge20;
65 +
  @merge20
66 +
    load w32 %21 %12 0;
67 +
    ret %21;
68 +
}
test/tests/ref.qualified.static.rad added +12 -0
1 +
//! returns: 42
2 +
3 +
mod storage;
4 +
5 +
/// Update a statically stored scalar through a checked mutable reference.
6 +
fn update(value: &mut i32) { set *value = 42; }
7 +
8 +
/// Return the value written through the qualified reference.
9 +
@default fn main() -> i32 {
10 +
    update(&mut storage::VALUE);
11 +
    return storage::VALUE;
12 +
}
test/tests/ref.qualified.static/storage.rad added +4 -0
1 +
//! Storage for the qualified static reference test.
2 +
3 +
/// Mutable scalar used through a module-qualified checked borrow.
4 +
export static VALUE: i32 = 7;
test/tests/regions.body.scope.rad added +9 -0
1 +
// Function bodies use the same region identity as their signatures.
2 +
3 +
fn read_1 'r (p: &'r u8) -> u8 { let q: &'r u8 = p; return *q; }
4 +
5 +
fn read_2 'r (p: &'r [u8]) -> u8 { let q: &'r [u8] = p; return q[0]; }
6 +
7 +
fn consume_3(p: &u8) {}
8 +
9 +
fn call_3 'r (p: &'r u8) { consume_3(p); }
test/tests/regions.body.scope.ril added +31 -0
1 +
fn w8 $read_1(w64 %0) {
2 +
  @entry0
3 +
    load w8 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w8 $read_2(w64 %0) {
8 +
  @entry0
9 +
    reserve %1 16 8;
10 +
    blit %1 %0 16;
11 +
    load w32 %2 %1 8;
12 +
    br.ult w32 0 %2 @guard#pass1 @guard#trap2;
13 +
  @guard#pass1
14 +
    load w64 %3 %1 0;
15 +
    load w8 %4 %3 0;
16 +
    ret %4;
17 +
  @guard#trap2
18 +
    ebreak;
19 +
    unreachable;
20 +
}
21 +
22 +
fn w64 $consume_3(w64 %0) {
23 +
  @entry0
24 +
    ret;
25 +
}
26 +
27 +
fn w64 $call_3(w64 %0) {
28 +
  @entry0
29 +
    call w64 $consume_3(%0);
30 +
    ret;
31 +
}
test/tests/regions.borrow.calls.rad added +30 -0
1 +
//! returns: 42
2 +
3 +
record Pair {
4 +
    left: u32,
5 +
    right: u32,
6 +
}
7 +
8 +
fn read 'r (p: &'r u32) -> u32 { return *p; }
9 +
fn bump 'r (p: &'r mut u32) { set *p += 1; }
10 +
fn apply 'r (p: &'r u32, op: fn(&'r u32) -> u32) -> u32 { return op(p); }
11 +
12 +
fn recurse 'r (p: &'r u32, depth: u32) -> u32 {
13 +
    if depth == 0 {
14 +
        return read(p);
15 +
    }
16 +
    return recurse(p, depth - 1);
17 +
}
18 +
19 +
@default fn main() -> u32 {
20 +
    let mut pair = Pair { left: 20, right: 21 };
21 +
    let left: 'whole = &mut pair.left, right = &mut pair.right in {
22 +
        let p: 'change = &mut *left in { bump(p); }
23 +
        let l: 'child = &*left, r = &*right in {
24 +
            assert apply(l, read 'child) == 21;
25 +
            assert recurse(r, 2) == 21;
26 +
        }
27 +
        set *left += *right;
28 +
    }
29 +
    return pair.left;
30 +
}
test/tests/regions.borrow.calls.ril added +57 -0
1 +
fn w32 $read(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w64 $bump(w64 %0) {
8 +
  @entry0
9 +
    load w32 %1 %0 0;
10 +
    add w32 %2 %1 1;
11 +
    store w32 %2 %0 0;
12 +
    ret;
13 +
}
14 +
15 +
fn w32 $apply(w64 %0, w64 %1) {
16 +
  @entry0
17 +
    call w32 %2 %1(%0);
18 +
    ret %2;
19 +
}
20 +
21 +
fn w32 $recurse(w64 %0, w32 %1) {
22 +
  @entry0
23 +
    br.eq w32 %1 0 @then1 @merge2;
24 +
  @then1
25 +
    call w32 %2 $read(%0);
26 +
    ret %2;
27 +
  @merge2
28 +
    sub w32 %3 %1 1;
29 +
    call w32 %4 $recurse(%0, %3);
30 +
    ret %4;
31 +
}
32 +
33 +
fn w32 $main() {
34 +
  @entry0
35 +
    reserve %0 8 4;
36 +
    store w32 20 %0 0;
37 +
    store w32 21 %0 4;
38 +
    add w64 %1 %0 4;
39 +
    call w64 $bump(%0);
40 +
    copy %2 $read;
41 +
    call w32 %3 $apply(%0, %2);
42 +
    br.eq w32 %3 21 @assert.ok2 @assert.fail1;
43 +
  @assert.fail1
44 +
    unreachable;
45 +
  @assert.ok2
46 +
    call w32 %4 $recurse(%1, 2);
47 +
    br.eq w32 %4 21 @assert.ok4 @assert.fail3;
48 +
  @assert.fail3
49 +
    unreachable;
50 +
  @assert.ok4
51 +
    load w32 %5 %0 0;
52 +
    load w32 %6 %1 0;
53 +
    add w32 %7 %5 %6;
54 +
    store w32 %7 %0 0;
55 +
    load w32 %8 %0 0;
56 +
    ret %8;
57 +
}
test/tests/regions.borrow.control.rad added +32 -0
1 +
//! returns: 42
2 +
3 +
union Failure { Failed }
4 +
5 +
fn fail 'r (p: &'r mut u32) throws (Failure) {
6 +
    set *p += 1;
7 +
    throw Failure::Failed;
8 +
}
9 +
10 +
@default fn main() -> u32 {
11 +
    let mut value: u32 = 37;
12 +
    for i in 0..3 {
13 +
        let p: 'iteration = &mut value in {
14 +
            set *p += 1;
15 +
            if i < 2 {
16 +
                continue;
17 +
            }
18 +
            break;
19 +
        }
20 +
    }
21 +
    let p: 'errors = &mut value in {
22 +
        let q: 'first = &mut *p in {
23 +
            try fail(q) catch {
24 +
            };
25 +
        }
26 +
        let q: 'second = &mut *p in {
27 +
            try fail(q) catch {
28 +
            };
29 +
        }
30 +
    }
31 +
    return value;
32 +
}
test/tests/regions.borrow.control.ril added +53 -0
1 +
fn w64 $fail(w64 %0, w64 %1) {
2 +
  @entry0
3 +
    load w32 %2 %1 0;
4 +
    add w32 %3 %2 1;
5 +
    store w32 %3 %1 0;
6 +
    reserve %4 9 8;
7 +
    store w64 1 %4 0;
8 +
    store w8 0 %4 8;
9 +
    blit %0 %4 9;
10 +
    ret %0;
11 +
}
12 +
13 +
fn w32 $main() {
14 +
  @entry0
15 +
    reserve %0 4 4;
16 +
    store w32 37 %0 0;
17 +
    jmp @loop1(0, %0);
18 +
  @loop1(w64 %1, w32 %2)
19 +
    br.slt w64 %1 3 @body2 @merge3;
20 +
  @body2
21 +
    load w32 %3 %2 0;
22 +
    add w32 %4 %3 1;
23 +
    store w32 %4 %2 0;
24 +
    br.slt w64 %1 2 @then4 @merge5;
25 +
  @merge3
26 +
    reserve %7 9 8;
27 +
    call w64 %8 $fail(%7, %2);
28 +
    load w64 %9 %8 0;
29 +
    br.ne w32 %9 0 @err8 @ok7;
30 +
  @then4
31 +
    jmp @step6;
32 +
  @merge5
33 +
    jmp @merge3;
34 +
  @step6
35 +
    add w64 %5 %1 1;
36 +
    jmp @loop1(%5, %2);
37 +
  @ok7
38 +
    jmp @merge9;
39 +
  @err8
40 +
    jmp @merge9;
41 +
  @merge9
42 +
    reserve %11 9 8;
43 +
    call w64 %12 $fail(%11, %2);
44 +
    load w64 %13 %12 0;
45 +
    br.ne w32 %13 0 @err11 @ok10;
46 +
  @ok10
47 +
    jmp @merge12;
48 +
  @err11
49 +
    jmp @merge12;
50 +
  @merge12
51 +
    load w32 %16 %2 0;
52 +
    ret %16;
53 +
}
test/tests/regions.borrow.erasure.rad added +9 -0
1 +
//! returns: 42
2 +
3 +
fn bump 'r (p: &'r mut u32) { set *p += 1; }
4 +
@default fn main() -> u32 {
5 +
    let mut x: u32 = 40;
6 +
    let p: 'a = &mut x in { bump(p); }
7 +
    let p: 'b = &mut x in { bump 'b (p); }
8 +
    return x;
9 +
}
test/tests/regions.borrow.erasure.ril added +17 -0
1 +
fn w64 $bump(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    add w32 %2 %1 1;
5 +
    store w32 %2 %0 0;
6 +
    ret;
7 +
}
8 +
9 +
fn w32 $main() {
10 +
  @entry0
11 +
    reserve %0 4 4;
12 +
    store w32 40 %0 0;
13 +
    call w64 $bump(%0);
14 +
    call w64 $bump(%0);
15 +
    load w32 %1 %0 0;
16 +
    ret %1;
17 +
}
test/tests/regions.borrow.headers.rad added +11 -0
1 +
//! returns: 42
2 +
3 +
@default fn main() -> u32 {
4 +
    let x: u32 = 20;
5 +
    let a: u32 = 22;
6 +
    let x: 'r = &a, other = &x in {
7 +
        assert *x == 22;
8 +
        assert *other == 20;
9 +
        return *x + *other;
10 +
    }
11 +
}
test/tests/regions.borrow.headers.ril added +21 -0
1 +
fn w32 $main() {
2 +
  @entry0
3 +
    reserve %0 4 4;
4 +
    store w32 20 %0 0;
5 +
    reserve %1 4 4;
6 +
    store w32 22 %1 0;
7 +
    load w32 %2 %1 0;
8 +
    br.eq w32 %2 22 @assert.ok2 @assert.fail1;
9 +
  @assert.fail1
10 +
    unreachable;
11 +
  @assert.ok2
12 +
    load w32 %3 %0 0;
13 +
    br.eq w32 %3 20 @assert.ok4 @assert.fail3;
14 +
  @assert.fail3
15 +
    unreachable;
16 +
  @assert.ok4
17 +
    load w32 %4 %1 0;
18 +
    load w32 %5 %0 0;
19 +
    add w32 %6 %4 %5;
20 +
    ret %6;
21 +
}
test/tests/regions.borrow.local.rad added +5 -0
1 +
// A block-local value cannot supply storage for the whole enclosing region.
2 +
3 +
fn read 'r (p: &'r u32) -> u32 { return *p; }
4 +
5 +
fn run() { let x: u32 = 1; let p: 'outer = &x in { let y: u32 = 2; let q: 'inner = &y in { assert read(q) == 2; } } }
test/tests/regions.borrow.local.ril added +19 -0
1 +
fn w32 $read(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w64 $run() {
8 +
  @entry0
9 +
    reserve %0 4 4;
10 +
    store w32 1 %0 0;
11 +
    reserve %1 4 4;
12 +
    store w32 2 %1 0;
13 +
    call w32 %2 $read(%1);
14 +
    br.eq w32 %2 2 @assert.ok2 @assert.fail1;
15 +
  @assert.fail1
16 +
    unreachable;
17 +
  @assert.ok2
18 +
    ret;
19 +
}
test/tests/regions.borrow.siblings.rad added +3 -0
1 +
// Borrow headers require existing places and accessible, distinct region names.
2 +
3 +
fn run() { let x: u32 = 1; let p: 'r = &x in {} let p: 'r = &x in {} }
test/tests/regions.borrow.siblings.ril added +6 -0
1 +
fn w64 $run() {
2 +
  @entry0
3 +
    reserve %0 4 4;
4 +
    store w32 1 %0 0;
5 +
    ret;
6 +
}
test/tests/regions.borrow.valid.rad added +17 -0
1 +
// Concrete borrow blocks supply named regions to generic functions.
2 +
3 +
fn read_1 'r (p: &'r u32) -> u32 { return *p; }
4 +
5 +
fn run_1() -> u32 { let x: u32 = 42; let p: 'local = &x in { return read_1(p); } }
6 +
7 +
fn bump_2 'r (p: &'r mut u32) { set *p += 1; }
8 +
9 +
fn run_2() -> u32 { let mut x: u32 = 41; let p: 'local = &mut x in { bump_2(p); } return x; }
10 +
11 +
fn run_3() { let mut x: u32 = 1; let p: 'a = &mut x in { let q: 'b = &mut *p in { set *q = 2; } set *p = 3; } set x = 4; }
12 +
13 +
fn run_4 'a (p: &'a mut u32) { let q: 'b = &mut *p where 'a: 'b in { set *q = 2; } set *p = 3; }
14 +
15 +
record Pair_5 { a: u32, b: u32 }
16 +
17 +
fn run_5() { let mut pair = Pair_5 { a: 1, b: 2 }; let a: 'r = &mut pair.a, b = &mut pair.b in { set *a = *b; } }
test/tests/regions.borrow.valid.ril added +58 -0
1 +
fn w32 $read_1(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w32 $run_1() {
8 +
  @entry0
9 +
    reserve %0 4 4;
10 +
    store w32 42 %0 0;
11 +
    call w32 %1 $read_1(%0);
12 +
    ret %1;
13 +
}
14 +
15 +
fn w64 $bump_2(w64 %0) {
16 +
  @entry0
17 +
    load w32 %1 %0 0;
18 +
    add w32 %2 %1 1;
19 +
    store w32 %2 %0 0;
20 +
    ret;
21 +
}
22 +
23 +
fn w32 $run_2() {
24 +
  @entry0
25 +
    reserve %0 4 4;
26 +
    store w32 41 %0 0;
27 +
    call w64 $bump_2(%0);
28 +
    load w32 %1 %0 0;
29 +
    ret %1;
30 +
}
31 +
32 +
fn w64 $run_3() {
33 +
  @entry0
34 +
    reserve %0 4 4;
35 +
    store w32 1 %0 0;
36 +
    store w32 2 %0 0;
37 +
    store w32 3 %0 0;
38 +
    store w32 4 %0 0;
39 +
    ret;
40 +
}
41 +
42 +
fn w64 $run_4(w64 %0) {
43 +
  @entry0
44 +
    store w32 2 %0 0;
45 +
    store w32 3 %0 0;
46 +
    ret;
47 +
}
48 +
49 +
fn w64 $run_5() {
50 +
  @entry0
51 +
    reserve %0 8 4;
52 +
    store w32 1 %0 0;
53 +
    store w32 2 %0 4;
54 +
    add w64 %1 %0 4;
55 +
    load w32 %2 %1 0;
56 +
    store w32 %2 %0 0;
57 +
    ret;
58 +
}
test/tests/regions.calls.callback.rad added +7 -0
1 +
// Callback signatures preserve the same region substitution as data arguments.
2 +
3 +
fn read 'r (p: &'r u32) -> u32 { return *p; }
4 +
5 +
fn useOp 'r (p: &'r u32, op: fn(&'r u32) -> u32) -> u32 { return op(p); }
6 +
7 +
fn relay 's (p: &'s u32) -> u32 { return useOp(p, read 's); }
test/tests/regions.calls.callback.ril added +18 -0
1 +
fn w32 $read(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w32 $useOp(w64 %0, w64 %1) {
8 +
  @entry0
9 +
    call w32 %2 %1(%0);
10 +
    ret %2;
11 +
}
12 +
13 +
fn w32 $relay(w64 %0) {
14 +
  @entry0
15 +
    copy %1 $read;
16 +
    call w32 %2 $useOp(%0, %1);
17 +
    ret %2;
18 +
}
test/tests/regions.calls.inferred.rad added +24 -0
1 +
// Calls bind symbolic regions to the caller's reference regions.
2 +
3 +
fn read_1 'r (p: &'r u32) -> u32 { return *p; }
4 +
5 +
fn relay_1 's (p: &'s u32) -> u32 { return read_1(p); }
6 +
7 +
fn read_2 'r (p: &'r [u32]) -> u32 { return p[0]; }
8 +
9 +
fn relay_2 's (p: &'s [u32]) -> u32 { return read_2(p); }
10 +
11 +
fn bump_3 'r (p: &'r mut u32) { set *p += 1; }
12 +
13 +
fn relay_3 's (p: &'s mut u32) {
14 +
    let q: 'first = &mut *p where 's: 'first in { bump_3(q); }
15 +
    let q: 'second = &mut *p where 's: 'second in { bump_3(q); }
16 +
}
17 +
18 +
fn read_4 'r (p: &'r u32) -> u32 { return *p; }
19 +
20 +
fn relay_4 's (p: &'s u32) -> u32 { let op = read_4 's; return op(p); }
21 +
22 +
fn answer_5 'r () -> u32 { return 42; }
23 +
24 +
fn relay_5 's () -> u32 { return answer_5 's (); }
test/tests/regions.calls.inferred.ril added +69 -0
1 +
fn w32 $read_1(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w32 $relay_1(w64 %0) {
8 +
  @entry0
9 +
    call w32 %1 $read_1(%0);
10 +
    ret %1;
11 +
}
12 +
13 +
fn w32 $read_2(w64 %0) {
14 +
  @entry0
15 +
    load w32 %1 %0 8;
16 +
    br.ult w32 0 %1 @guard#pass1 @guard#trap2;
17 +
  @guard#pass1
18 +
    load w64 %2 %0 0;
19 +
    load w32 %3 %2 0;
20 +
    ret %3;
21 +
  @guard#trap2
22 +
    ebreak;
23 +
    unreachable;
24 +
}
25 +
26 +
fn w32 $relay_2(w64 %0) {
27 +
  @entry0
28 +
    call w32 %1 $read_2(%0);
29 +
    ret %1;
30 +
}
31 +
32 +
fn w64 $bump_3(w64 %0) {
33 +
  @entry0
34 +
    load w32 %1 %0 0;
35 +
    add w32 %2 %1 1;
36 +
    store w32 %2 %0 0;
37 +
    ret;
38 +
}
39 +
40 +
fn w64 $relay_3(w64 %0) {
41 +
  @entry0
42 +
    call w64 $bump_3(%0);
43 +
    call w64 $bump_3(%0);
44 +
    ret;
45 +
}
46 +
47 +
fn w32 $read_4(w64 %0) {
48 +
  @entry0
49 +
    load w32 %1 %0 0;
50 +
    ret %1;
51 +
}
52 +
53 +
fn w32 $relay_4(w64 %0) {
54 +
  @entry0
55 +
    copy %1 $read_4;
56 +
    call w32 %2 %1(%0);
57 +
    ret %2;
58 +
}
59 +
60 +
fn w32 $answer_5() {
61 +
  @entry0
62 +
    ret 42;
63 +
}
64 +
65 +
fn w32 $relay_5() {
66 +
  @entry0
67 +
    call w32 %0 $answer_5();
68 +
    ret %0;
69 +
}
test/tests/regions.calls.nil.rad added +38 -0
1 +
//! returns: 42
2 +
3 +
/// A shared value stored inline in an optional result.
4 +
record View: 'r + Copy {
5 +
    /// Referenced value.
6 +
    value: &'r u32,
7 +
}
8 +
9 +
/// Select a nullable reference, with a fallback.
10 +
fn select 'r (first: &'r u32, second: ?&'r u32) -> u32 {
11 +
    if let value = second {
12 +
        return *value;
13 +
    }
14 +
    return *first;
15 +
}
16 +
17 +
/// Infer the region from an argument after the nil argument.
18 +
fn fallback 'r (first: ?View 'r, second: &'r u32) -> u32 {
19 +
    if let view = first {
20 +
        return *view.value;
21 +
    }
22 +
    return *second;
23 +
}
24 +
25 +
/// Complete both branches of an initially untyped nil expression.
26 +
fn conditional 'r (value: &'r u32, flag: bool) -> u32 {
27 +
    return select(value, nil if flag else nil);
28 +
}
29 +
30 +
@default fn main() -> u32 {
31 +
    let value: u32 = 42;
32 +
    let shared: 'r = &value in {
33 +
        assert select(shared, nil) == 42;
34 +
        assert fallback(nil, shared) == 42;
35 +
        assert conditional(shared, true) == 42;
36 +
        return conditional(shared, false);
37 +
    }
38 +
}
test/tests/regions.calls.nil.ril added +67 -0
1 +
fn w32 $select(w64 %0, w64 %1) {
2 +
  @entry0
3 +
    br.ne w32 %1 0 @then1 @else2;
4 +
  @then1
5 +
    load w32 %2 %1 0;
6 +
    ret %2;
7 +
  @else2
8 +
    jmp @merge3;
9 +
  @merge3
10 +
    load w32 %3 %0 0;
11 +
    ret %3;
12 +
}
13 +
14 +
fn w32 $fallback(w64 %0, w64 %1) {
15 +
  @entry0
16 +
    reserve %2 16 8;
17 +
    blit %2 %0 16;
18 +
    load w8 %3 %2 0;
19 +
    br.ne w32 %3 0 @then1 @else2;
20 +
  @then1
21 +
    add w64 %4 %2 8;
22 +
    load w64 %5 %4 0;
23 +
    load w32 %6 %5 0;
24 +
    ret %6;
25 +
  @else2
26 +
    jmp @merge3;
27 +
  @merge3
28 +
    load w32 %7 %1 0;
29 +
    ret %7;
30 +
}
31 +
32 +
fn w32 $conditional(w64 %0, w8 %1) {
33 +
  @entry0
34 +
    br.ne w32 %1 0 @cond#then1 @cond#else2;
35 +
  @cond#then1
36 +
    jmp @cond#merge3(0);
37 +
  @cond#else2
38 +
    jmp @cond#merge3(0);
39 +
  @cond#merge3(w64 %2)
40 +
    call w32 %3 $select(%0, %2);
41 +
    ret %3;
42 +
}
43 +
44 +
fn w32 $main() {
45 +
  @entry0
46 +
    reserve %0 4 4;
47 +
    store w32 42 %0 0;
48 +
    call w32 %1 $select(%0, 0);
49 +
    br.eq w32 %1 42 @assert.ok2 @assert.fail1;
50 +
  @assert.fail1
51 +
    unreachable;
52 +
  @assert.ok2
53 +
    reserve %2 16 8;
54 +
    store w8 0 %2 0;
55 +
    call w32 %3 $fallback(%2, %0);
56 +
    br.eq w32 %3 42 @assert.ok4 @assert.fail3;
57 +
  @assert.fail3
58 +
    unreachable;
59 +
  @assert.ok4
60 +
    call w32 %4 $conditional(%0, 1);
61 +
    br.eq w32 %4 42 @assert.ok6 @assert.fail5;
62 +
  @assert.fail5
63 +
    unreachable;
64 +
  @assert.ok6
65 +
    call w32 %5 $conditional(%0, 0);
66 +
    ret %5;
67 +
}
test/tests/regions.calls.ownership.rad added +21 -0
1 +
//! returns: 42
2 +
3 +
fn temporary(p: &mut u32) { set *p += 1; }
4 +
fn take 'r (p: &'r mut u32) { set *p += 1; }
5 +
fn forward 'r (p: &'r mut u32) { take(p); }
6 +
fn read 'r (p: &'r u32) -> u32 { return *p; }
7 +
8 +
@default fn main() -> u32 {
9 +
    let mut value: u32 = 38;
10 +
    let p: 'outer = &mut value in {
11 +
        temporary(p);
12 +
        temporary(p);
13 +
        let q: 'first = &mut *p in { take(q); }
14 +
        let q: 'second = &mut *p in { forward(q); }
15 +
        let q: 'shared = &*p in {
16 +
            assert read(q) == 42;
17 +
            assert read(q) == 42;
18 +
        }
19 +
    }
20 +
    return value;
21 +
}
test/tests/regions.calls.ownership.ril added +49 -0
1 +
fn w64 $temporary(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    add w32 %2 %1 1;
5 +
    store w32 %2 %0 0;
6 +
    ret;
7 +
}
8 +
9 +
fn w64 $take(w64 %0) {
10 +
  @entry0
11 +
    load w32 %1 %0 0;
12 +
    add w32 %2 %1 1;
13 +
    store w32 %2 %0 0;
14 +
    ret;
15 +
}
16 +
17 +
fn w64 $forward(w64 %0) {
18 +
  @entry0
19 +
    call w64 $take(%0);
20 +
    ret;
21 +
}
22 +
23 +
fn w32 $read(w64 %0) {
24 +
  @entry0
25 +
    load w32 %1 %0 0;
26 +
    ret %1;
27 +
}
28 +
29 +
fn w32 $main() {
30 +
  @entry0
31 +
    reserve %0 4 4;
32 +
    store w32 38 %0 0;
33 +
    call w64 $temporary(%0);
34 +
    call w64 $temporary(%0);
35 +
    call w64 $take(%0);
36 +
    call w64 $forward(%0);
37 +
    call w32 %1 $read(%0);
38 +
    br.eq w32 %1 42 @assert.ok2 @assert.fail1;
39 +
  @assert.fail1
40 +
    unreachable;
41 +
  @assert.ok2
42 +
    call w32 %2 $read(%0);
43 +
    br.eq w32 %2 42 @assert.ok4 @assert.fail3;
44 +
  @assert.fail3
45 +
    unreachable;
46 +
  @assert.ok4
47 +
    load w32 %3 %0 0;
48 +
    ret %3;
49 +
}
test/tests/regions.calls.parents.rad added +5 -0
1 +
// Inferred and explicit region arguments must satisfy declared parent relations.
2 +
3 +
fn pair 'p 'c (p: &'p u32, c: &'c u32) where 'p: 'c {}
4 +
5 +
fn relay 'a 'b (a: &'a u32, b: &'b u32) where 'a: 'b { pair(a, b); pair 'a 'b (a, b); pair 'a 'a (a, a); }
test/tests/regions.calls.parents.ril added +12 -0
1 +
fn w64 $pair(w64 %0, w64 %1) {
2 +
  @entry0
3 +
    ret;
4 +
}
5 +
6 +
fn w64 $relay(w64 %0, w64 %1) {
7 +
  @entry0
8 +
    call w64 $pair(%0, %1);
9 +
    call w64 $pair(%0, %1);
10 +
    call w64 $pair(%0, %0);
11 +
    ret;
12 +
}
test/tests/regions.calls.raw.rad added +15 -0
1 +
//! returns: 42
2 +
3 +
record View: 'r + Copy { value: &'r u32 }
4 +
5 +
fn read 'r (view: *unsafe View 'r) -> u32 {
6 +
    unsafe { return *view.value; }
7 +
}
8 +
9 +
@default unsafe fn main() -> u32 {
10 +
    let value: u32 = 21;
11 +
    let p: 'data = &value in {
12 +
        let view: View 'data = View { value: p };
13 +
        return read(&view) + read(&view if true else &view);
14 +
    }
15 +
}
test/tests/regions.calls.raw.ril added +25 -0
1 +
fn w32 $read(w64 %0) {
2 +
  @entry0
3 +
    load w64 %1 %0 0;
4 +
    load w32 %2 %1 0;
5 +
    ret %2;
6 +
}
7 +
8 +
fn w32 $main() {
9 +
  @entry0
10 +
    reserve %0 4 4;
11 +
    store w32 21 %0 0;
12 +
    reserve %1 8 8;
13 +
    store w64 %0 %1 0;
14 +
    call w32 %2 $read(%1);
15 +
    copy %3 1;
16 +
    br.ne w32 %3 0 @cond#then1 @cond#else2;
17 +
  @cond#then1
18 +
    jmp @cond#merge3(%1);
19 +
  @cond#else2
20 +
    jmp @cond#merge3(%1);
21 +
  @cond#merge3(w64 %4)
22 +
    call w32 %5 $read(%4);
23 +
    add w32 %6 %2 %5;
24 +
    ret %6;
25 +
}
test/tests/regions.calls.recursive.rad added +17 -0
1 +
// Recursive applications preserve one checked source signature.
2 +
3 +
fn recurse_1 'r (p: &'r u32, depth: u32) -> u32 {
4 +
    if depth == 0 {
5 +
        return *p;
6 +
    }
7 +
    return recurse_1(p, depth - 1);
8 +
}
9 +
10 +
fn left_2 'a (p: &'a u32, depth: u32) -> u32 {
11 +
    if depth == 0 {
12 +
        return *p;
13 +
    }
14 +
    return right_2(p, depth - 1);
15 +
}
16 +
17 +
fn right_2 'b (p: &'b u32, depth: u32) -> u32 { return left_2(p, depth); }
test/tests/regions.calls.recursive.ril added +29 -0
1 +
fn w32 $recurse_1(w64 %0, w32 %1) {
2 +
  @entry0
3 +
    br.eq w32 %1 0 @then1 @merge2;
4 +
  @then1
5 +
    load w32 %2 %0 0;
6 +
    ret %2;
7 +
  @merge2
8 +
    sub w32 %3 %1 1;
9 +
    call w32 %4 $recurse_1(%0, %3);
10 +
    ret %4;
11 +
}
12 +
13 +
fn w32 $left_2(w64 %0, w32 %1) {
14 +
  @entry0
15 +
    br.eq w32 %1 0 @then1 @merge2;
16 +
  @then1
17 +
    load w32 %2 %0 0;
18 +
    ret %2;
19 +
  @merge2
20 +
    sub w32 %3 %1 1;
21 +
    call w32 %4 $right_2(%0, %3);
22 +
    ret %4;
23 +
}
24 +
25 +
fn w32 $right_2(w64 %0, w32 %1) {
26 +
  @entry0
27 +
    call w32 %2 $left_2(%0, %1);
28 +
    ret %2;
29 +
}
test/tests/regions.cell.graph.rad added +46 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
/// State with an immutable link into the graph.
7 +
union State: 'r + Copy {
8 +
    Pending,
9 +
    Ready(&'r Body 'r),
10 +
}
11 +
12 +
/// Graph node that retains its shared state cell.
13 +
record Body: 'r + Copy {
14 +
    /// State shared by graph aliases.
15 +
    state: &'r cell State 'r,
16 +
}
17 +
18 +
/// Read a retained graph link after the cell changes its active variant.
19 +
fn snapshot 'r (state: &'r cell State 'r) -> u32 {
20 +
    let previous = *state;
21 +
    set *state = State 'r::Pending;
22 +
    match previous {
23 +
        case State 'r::Ready(body) => {
24 +
            match *body.state {
25 +
                case State 'r::Pending => return 42,
26 +
                else => panic,
27 +
            }
28 +
        },
29 +
        else => panic,
30 +
    }
31 +
}
32 +
33 +
@default unsafe fn main() -> u32 {
34 +
    static DATA: [u8; 1024] = [0; 1024];
35 +
    let mut arena = alloc::new(&mut DATA[..]);
36 +
    let mut result: u32 = 0;
37 +
    use arena as graph in {
38 +
        let initial = try! graph.new(State 'graph::Pending);
39 +
        let state = initial as &'graph cell State 'graph;
40 +
        let body: &'graph Body 'graph = try! graph.new(Body 'graph { state });
41 +
        set *state = State 'graph::Ready(body);
42 +
        set result = snapshot(state);
43 +
    }
44 +
    alloc::reset(&mut arena);
45 +
    return result;
46 +
}
test/tests/regions.cell.graph.ril added +105 -0
1 +
data mut $"regions.cell.graph::regions.cell.graph::main$nominal$DATA" align 1 {
2 +
    w8 0 * 1024;
3 +
}
4 +
5 +
fn w32 $"regions.cell.graph::snapshot"(w64 %0) {
6 +
  @entry0
7 +
    reserve %1 16 8;
8 +
    blit %1 %0 16;
9 +
    reserve %2 16 8;
10 +
    store w8 0 %2 0;
11 +
    blit %0 %2 16;
12 +
    reserve %3 16 8;
13 +
    blit %3 %1 16;
14 +
    jmp @arm1;
15 +
  @arm1
16 +
    load w8 %4 %3 0;
17 +
    br.eq w8 %4 1 @case2 @arm3;
18 +
  @case2
19 +
    load w64 %5 %3 8;
20 +
    load w64 %6 %5 0;
21 +
    reserve %7 16 8;
22 +
    blit %7 %6 16;
23 +
    reserve %8 16 8;
24 +
    blit %8 %7 16;
25 +
    jmp @arm4;
26 +
  @arm3
27 +
    jmp @else9;
28 +
  @arm4
29 +
    load w8 %9 %8 0;
30 +
    br.eq w8 %9 0 @case5 @arm6;
31 +
  @case5
32 +
    ret 42;
33 +
  @arm6
34 +
    jmp @else7;
35 +
  @else7
36 +
    unreachable;
37 +
  @else9
38 +
    unreachable;
39 +
}
40 +
41 +
fn w32 $"regions.cell.graph::main"() {
42 +
  @entry0
43 +
    copy %0 $"regions.cell.graph::regions.cell.graph::main$nominal$DATA";
44 +
    reserve %1 16 8;
45 +
    store w64 %0 %1 0;
46 +
    store w32 1024 %1 8;
47 +
    store w32 1024 %1 12;
48 +
    reserve %2 24 8;
49 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
50 +
    reserve %4 16 8;
51 +
    store w64 %3 %4 0;
52 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
53 +
    load w64 %5 %4 0;
54 +
    load w64 %6 %4 8;
55 +
    load w64 %7 %6 0;
56 +
    reserve %8 16 8;
57 +
    store w8 0 %8 0;
58 +
    reserve %9 16 8;
59 +
    blit %9 %8 16;
60 +
    reserve %10 16 8;
61 +
    call w64 %11 %7(%10, %5, 16, 8);
62 +
    load w64 %12 %11 0;
63 +
    reserve %13 8 8;
64 +
    br.ne w32 %12 0 @err2 @ok1;
65 +
  @ok1
66 +
    load w64 %14 %11 8;
67 +
    blit %14 %9 16;
68 +
    load w64 %15 %11 8;
69 +
    store w64 %15 %13 0;
70 +
    jmp @merge3;
71 +
  @err2
72 +
    unreachable;
73 +
  @merge3
74 +
    load w64 %16 %13 0;
75 +
    load w64 %17 %4 0;
76 +
    load w64 %18 %4 8;
77 +
    load w64 %19 %18 0;
78 +
    reserve %20 8 8;
79 +
    store w64 %16 %20 0;
80 +
    reserve %21 16 8;
81 +
    call w64 %22 %19(%21, %17, 8, 8);
82 +
    load w64 %23 %22 0;
83 +
    reserve %24 8 8;
84 +
    br.ne w32 %23 0 @err5 @ok4;
85 +
  @ok4
86 +
    load w64 %25 %22 8;
87 +
    blit %25 %20 8;
88 +
    load w64 %26 %22 8;
89 +
    store w64 %26 %24 0;
90 +
    jmp @merge6;
91 +
  @err5
92 +
    unreachable;
93 +
  @merge6
94 +
    load w64 %27 %24 0;
95 +
    reserve %28 8 8;
96 +
    store w64 %27 %28 0;
97 +
    reserve %29 16 8;
98 +
    store w8 1 %29 0;
99 +
    add w64 %30 %29 8;
100 +
    blit %30 %28 8;
101 +
    blit %16 %29 16;
102 +
    call w32 %31 $"regions.cell.graph::snapshot"(%16);
103 +
    call w64 $"std::lang::alloc::reset"(%3);
104 +
    ret %31;
105 +
}
test/tests/regions.cell.pointer.rad added +106 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
record Pair: Copy { a: u32, b: u32 }
7 +
record Entry: 'r + Copy { index: &'r cell u32 }
8 +
9 +
/// A copied union retains its reference after the cell changes its tag.
10 +
union Link: 'r + Copy { Value(&'r u32), Empty }
11 +
12 +
fn unionCell 'r (allocation: &Session 'r) -> u32 {
13 +
    let value = try! allocation.new(19 as u32);
14 +
    let shared: &'r u32 = value;
15 +
    let initial: Link 'r = Link::Value(shared);
16 +
    let storage = try! allocation.new(initial);
17 +
    let pointer = storage as &'r cell Link 'r;
18 +
    let snapshot = *pointer;
19 +
    set *pointer = Link::Empty;
20 +
    match *pointer {
21 +
        case Link::Empty => {
22 +
        },
23 +
        case Link::Value(_) => panic,
24 +
    }
25 +
    match snapshot {
26 +
        case Link::Value(retained) => return *retained,
27 +
        case Link::Empty => panic,
28 +
    }
29 +
}
30 +
31 +
fn local() -> u32 {
32 +
    let mut value: u32 = 0;
33 +
    {
34 +
        let pointer = &mut value as &cell u32;
35 +
        let alias = pointer;
36 +
        set *alias = 7;
37 +
        assert *pointer == 7;
38 +
        set *pointer = 8;
39 +
        assert *alias == 8;
40 +
        set *alias = 7;
41 +
    }
42 +
    return value;
43 +
}
44 +
45 +
fn update(pointer: *cell u32) { set *pointer = 20; }
46 +
fn read 'r (pointer: &'r cell u32) -> u32 { return *pointer; }
47 +
fn relay 'r (pointer: &'r cell u32) -> &'r cell u32 { return pointer; }
48 +
49 +
/// Count evaluations of a compound assignment target.
50 +
fn select(pointer: *cell u32, calls: *cell u32) -> *cell u32 {
51 +
    set *calls += 1;
52 +
    return pointer;
53 +
}
54 +
55 +
/// Replace shared storage while retaining a value argument snapshot.
56 +
fn replace 'r (snapshot: Pair, pointer: &'r cell Pair) -> u32 {
57 +
    set *pointer = Pair { a: 5, b: 6 };
58 +
    return snapshot.a;
59 +
}
60 +
61 +
@default fn main() -> u32 {
62 +
    assert local() == 7;
63 +
    assert @sizeOf(*cell u32) == @sizeOf(*mut u32);
64 +
    static VALUE: u32 = 0;
65 +
    let pointer: *mut u32 = &mut VALUE;
66 +
    let cell = pointer as *cell u32;
67 +
    let alias = cell;
68 +
    update(alias);
69 +
    assert *cell == 20;
70 +
    static CALLS: u32 = 0;
71 +
    let calls = &mut CALLS as *cell u32;
72 +
    set *select(cell, calls) += 1;
73 +
    assert *calls == 1;
74 +
    assert *cell == 21;
75 +
    set *cell = 20;
76 +
77 +
    static DATA: [u8; 256] = [0; 256];
78 +
    let mut arena = alloc::new(&mut DATA[..]);
79 +
    use arena as objects in {
80 +
        assert unionCell(&objects) == 19;
81 +
        let value = try! objects.new(22 as u32);
82 +
        let shared = value as &'objects cell u32;
83 +
        let optional: ?&'objects cell u32 = shared;
84 +
        if let present = optional {
85 +
            assert *present == 22;
86 +
        } else {
87 +
            panic;
88 +
        }
89 +
        let pointers = try! objects.fill(shared, 2);
90 +
        set *pointers[1] = 22;
91 +
        let entry: Entry 'objects = Entry { index: relay(shared) };
92 +
        let copy = entry;
93 +
        set *copy.index = 21;
94 +
        assert read(entry.index) == 21;
95 +
        set *shared = 22;
96 +
        let pair = try! objects.new(Pair { a: 1, b: 2 });
97 +
        let pairCell = pair as &'objects cell Pair;
98 +
        let snapshot = *pairCell;
99 +
        set *pairCell = Pair { a: 3, b: 4 };
100 +
        assert snapshot.a == 1 and snapshot.b == 2;
101 +
        assert (*pairCell).b == 4;
102 +
        assert replace(*pairCell, pairCell) == 3;
103 +
        assert (*pairCell).a == 5;
104 +
        return *cell + *shared;
105 +
    }
106 +
}
test/tests/regions.cell.pointer.ril added +358 -0
1 +
data mut $"regions.cell.pointer::regions.cell.pointer::main$nominal$VALUE" align 4 {
2 +
    w32 0;
3 +
}
4 +
5 +
data mut $"regions.cell.pointer::regions.cell.pointer::main$nominal$CALLS" align 4 {
6 +
    w32 0;
7 +
}
8 +
9 +
data mut $"regions.cell.pointer::regions.cell.pointer::main$nominal$DATA" align 1 {
10 +
    w8 0 * 256;
11 +
}
12 +
13 +
fn w32 $"regions.cell.pointer::unionCell"(w64 %0) {
14 +
  @entry0
15 +
    load w64 %1 %0 0;
16 +
    load w64 %2 %0 8;
17 +
    load w64 %3 %2 0;
18 +
    zext w32 %4 19;
19 +
    reserve %5 16 8;
20 +
    call w64 %6 %3(%5, %1, 4, 4);
21 +
    load w64 %7 %6 0;
22 +
    reserve %8 8 8;
23 +
    br.ne w32 %7 0 @err2 @ok1;
24 +
  @ok1
25 +
    load w64 %9 %6 8;
26 +
    store w32 %4 %9 0;
27 +
    load w64 %10 %6 8;
28 +
    store w64 %10 %8 0;
29 +
    jmp @merge3;
30 +
  @err2
31 +
    unreachable;
32 +
  @merge3
33 +
    load w64 %11 %8 0;
34 +
    reserve %12 8 8;
35 +
    store w64 %11 %12 0;
36 +
    reserve %13 16 8;
37 +
    store w8 0 %13 0;
38 +
    add w64 %14 %13 8;
39 +
    blit %14 %12 8;
40 +
    load w64 %15 %0 0;
41 +
    load w64 %16 %0 8;
42 +
    load w64 %17 %16 0;
43 +
    reserve %18 16 8;
44 +
    blit %18 %13 16;
45 +
    reserve %19 16 8;
46 +
    call w64 %20 %17(%19, %15, 16, 8);
47 +
    load w64 %21 %20 0;
48 +
    reserve %22 8 8;
49 +
    br.ne w32 %21 0 @err5 @ok4;
50 +
  @ok4
51 +
    load w64 %23 %20 8;
52 +
    blit %23 %18 16;
53 +
    load w64 %24 %20 8;
54 +
    store w64 %24 %22 0;
55 +
    jmp @merge6;
56 +
  @err5
57 +
    unreachable;
58 +
  @merge6
59 +
    load w64 %25 %22 0;
60 +
    reserve %26 16 8;
61 +
    blit %26 %25 16;
62 +
    reserve %27 16 8;
63 +
    store w8 1 %27 0;
64 +
    blit %25 %27 16;
65 +
    reserve %28 16 8;
66 +
    blit %28 %25 16;
67 +
    reserve %29 16 8;
68 +
    blit %29 %28 16;
69 +
    jmp @arm7;
70 +
  @arm7
71 +
    load w8 %30 %29 0;
72 +
    br.eq w8 %30 1 @case8 @arm9;
73 +
  @case8
74 +
    jmp @merge10;
75 +
  @arm9
76 +
    jmp @case11;
77 +
  @merge10
78 +
    reserve %31 16 8;
79 +
    blit %31 %26 16;
80 +
    jmp @arm13;
81 +
  @case11
82 +
    unreachable;
83 +
  @arm13
84 +
    load w8 %32 %31 0;
85 +
    br.eq w8 %32 0 @case14 @arm15;
86 +
  @case14
87 +
    load w64 %33 %31 8;
88 +
    load w32 %34 %33 0;
89 +
    ret %34;
90 +
  @arm15
91 +
    jmp @case16;
92 +
  @case16
93 +
    unreachable;
94 +
}
95 +
96 +
fn w32 $"regions.cell.pointer::local"() {
97 +
  @entry0
98 +
    reserve %0 4 4;
99 +
    store w32 0 %0 0;
100 +
    store w32 7 %0 0;
101 +
    load w32 %1 %0 0;
102 +
    br.eq w32 %1 7 @assert.ok2 @assert.fail1;
103 +
  @assert.fail1
104 +
    unreachable;
105 +
  @assert.ok2
106 +
    store w32 8 %0 0;
107 +
    load w32 %2 %0 0;
108 +
    br.eq w32 %2 8 @assert.ok4 @assert.fail3;
109 +
  @assert.fail3
110 +
    unreachable;
111 +
  @assert.ok4
112 +
    store w32 7 %0 0;
113 +
    load w32 %3 %0 0;
114 +
    ret %3;
115 +
}
116 +
117 +
fn w64 $"regions.cell.pointer::update"(w64 %0) {
118 +
  @entry0
119 +
    store w32 20 %0 0;
120 +
    ret;
121 +
}
122 +
123 +
fn w32 $"regions.cell.pointer::read"(w64 %0) {
124 +
  @entry0
125 +
    load w32 %1 %0 0;
126 +
    ret %1;
127 +
}
128 +
129 +
fn w64 $"regions.cell.pointer::relay"(w64 %0) {
130 +
  @entry0
131 +
    ret %0;
132 +
}
133 +
134 +
fn w64 $"regions.cell.pointer::select"(w64 %0, w64 %1) {
135 +
  @entry0
136 +
    load w32 %2 %1 0;
137 +
    add w32 %3 %2 1;
138 +
    store w32 %3 %1 0;
139 +
    ret %0;
140 +
}
141 +
142 +
fn w32 $"regions.cell.pointer::replace"(w64 %0, w64 %1) {
143 +
  @entry0
144 +
    reserve %2 8 4;
145 +
    store w32 5 %2 0;
146 +
    store w32 6 %2 4;
147 +
    blit %1 %2 8;
148 +
    load w32 %3 %0 0;
149 +
    ret %3;
150 +
}
151 +
152 +
fn w32 $"regions.cell.pointer::main"() {
153 +
  @entry0
154 +
    call w32 %0 $"regions.cell.pointer::local"();
155 +
    br.eq w32 %0 7 @assert.ok2 @assert.fail1;
156 +
  @assert.fail1
157 +
    unreachable;
158 +
  @assert.ok2
159 +
    br.eq w32 8 8 @assert.ok4 @assert.fail3;
160 +
  @assert.fail3
161 +
    unreachable;
162 +
  @assert.ok4
163 +
    copy %1 $"regions.cell.pointer::regions.cell.pointer::main$nominal$VALUE";
164 +
    call w64 $"regions.cell.pointer::update"(%1);
165 +
    load w32 %2 %1 0;
166 +
    br.eq w32 %2 20 @assert.ok6 @assert.fail5;
167 +
  @assert.fail5
168 +
    unreachable;
169 +
  @assert.ok6
170 +
    copy %3 $"regions.cell.pointer::regions.cell.pointer::main$nominal$CALLS";
171 +
    call w64 %4 $"regions.cell.pointer::select"(%1, %3);
172 +
    load w32 %5 %4 0;
173 +
    add w32 %6 %5 1;
174 +
    store w32 %6 %4 0;
175 +
    load w32 %7 %3 0;
176 +
    br.eq w32 %7 1 @assert.ok8 @assert.fail7;
177 +
  @assert.fail7
178 +
    unreachable;
179 +
  @assert.ok8
180 +
    load w32 %8 %1 0;
181 +
    br.eq w32 %8 21 @assert.ok10 @assert.fail9;
182 +
  @assert.fail9
183 +
    unreachable;
184 +
  @assert.ok10
185 +
    store w32 20 %1 0;
186 +
    copy %9 $"regions.cell.pointer::regions.cell.pointer::main$nominal$DATA";
187 +
    reserve %10 16 8;
188 +
    store w64 %9 %10 0;
189 +
    store w32 256 %10 8;
190 +
    store w32 256 %10 12;
191 +
    reserve %11 24 8;
192 +
    call w64 %12 $"std::lang::alloc::new"(%11, %10);
193 +
    reserve %13 16 8;
194 +
    store w64 %12 %13 0;
195 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %13 8;
196 +
    call w32 %14 $"regions.cell.pointer::unionCell"(%13);
197 +
    br.eq w32 %14 19 @assert.ok12 @assert.fail11;
198 +
  @assert.fail11
199 +
    unreachable;
200 +
  @assert.ok12
201 +
    load w64 %15 %13 0;
202 +
    load w64 %16 %13 8;
203 +
    load w64 %17 %16 0;
204 +
    zext w32 %18 22;
205 +
    reserve %19 16 8;
206 +
    call w64 %20 %17(%19, %15, 4, 4);
207 +
    load w64 %21 %20 0;
208 +
    reserve %22 8 8;
209 +
    br.ne w32 %21 0 @err14 @ok13;
210 +
  @ok13
211 +
    load w64 %23 %20 8;
212 +
    store w32 %18 %23 0;
213 +
    load w64 %24 %20 8;
214 +
    store w64 %24 %22 0;
215 +
    jmp @merge15;
216 +
  @err14
217 +
    unreachable;
218 +
  @merge15
219 +
    load w64 %25 %22 0;
220 +
    reserve %26 16 8;
221 +
    store w8 1 %26 0;
222 +
    store w64 %25 %26 8;
223 +
    reserve %27 16 8;
224 +
    blit %27 %26 16;
225 +
    reserve %28 16 8;
226 +
    blit %28 %27 16;
227 +
    load w8 %29 %28 0;
228 +
    br.ne w32 %29 0 @then16 @else17;
229 +
  @then16
230 +
    load w64 %30 %28 8;
231 +
    load w32 %31 %30 0;
232 +
    br.eq w32 %31 22 @assert.ok19 @assert.fail18;
233 +
  @else17
234 +
    unreachable;
235 +
  @assert.fail18
236 +
    unreachable;
237 +
  @assert.ok19
238 +
    jmp @merge20;
239 +
  @merge20
240 +
    load w64 %32 %13 0;
241 +
    load w64 %33 %13 8;
242 +
    load w64 %34 %33 8;
243 +
    reserve %35 24 8;
244 +
    call w64 %36 %34(%35, %32, 8, 8, 2);
245 +
    load w64 %37 %36 0;
246 +
    reserve %38 16 8;
247 +
    br.ne w32 %37 0 @err22 @ok21;
248 +
  @ok21
249 +
    load w64 %39 %36 8;
250 +
    jmp @fill23(0);
251 +
  @err22
252 +
    unreachable;
253 +
  @fill23(w32 %40)
254 +
    br.ult w32 %40 2 @fill24 @fill25;
255 +
  @fill24
256 +
    mul w64 %41 %40 8;
257 +
    add w64 %42 %39 %41;
258 +
    store w64 %25 %42 0;
259 +
    add w32 %43 %40 1;
260 +
    jmp @fill23(%43);
261 +
  @fill25
262 +
    add w64 %44 %36 8;
263 +
    blit %38 %44 16;
264 +
    jmp @merge26;
265 +
  @merge26
266 +
    load w32 %45 %38 8;
267 +
    br.ult w32 1 %45 @guard#pass27 @guard#trap28;
268 +
  @guard#pass27
269 +
    load w64 %46 %38 0;
270 +
    mul w64 %47 1 8;
271 +
    add w64 %48 %46 %47;
272 +
    load w64 %49 %48 0;
273 +
    store w32 22 %49 0;
274 +
    reserve %50 8 8;
275 +
    call w64 %52 $"regions.cell.pointer::relay"(%25);
276 +
    store w64 %52 %50 0;
277 +
    reserve %53 8 8;
278 +
    blit %53 %50 8;
279 +
    load w64 %54 %53 0;
280 +
    store w32 21 %54 0;
281 +
    load w64 %55 %50 0;
282 +
    call w32 %56 $"regions.cell.pointer::read"(%55);
283 +
    br.eq w32 %56 21 @assert.ok30 @assert.fail29;
284 +
  @guard#trap28
285 +
    ebreak;
286 +
    unreachable;
287 +
  @assert.fail29
288 +
    unreachable;
289 +
  @assert.ok30
290 +
    store w32 22 %25 0;
291 +
    load w64 %58 %13 0;
292 +
    load w64 %59 %13 8;
293 +
    load w64 %60 %59 0;
294 +
    reserve %61 8 4;
295 +
    store w32 1 %61 0;
296 +
    store w32 2 %61 4;
297 +
    reserve %62 16 8;
298 +
    call w64 %63 %60(%62, %58, 8, 4);
299 +
    load w64 %64 %63 0;
300 +
    reserve %65 8 8;
301 +
    br.ne w32 %64 0 @err32 @ok31;
302 +
  @ok31
303 +
    load w64 %66 %63 8;
304 +
    blit %66 %61 8;
305 +
    load w64 %67 %63 8;
306 +
    store w64 %67 %65 0;
307 +
    jmp @merge33;
308 +
  @err32
309 +
    unreachable;
310 +
  @merge33
311 +
    load w64 %68 %65 0;
312 +
    reserve %69 8 4;
313 +
    blit %69 %68 8;
314 +
    reserve %70 8 4;
315 +
    store w32 3 %70 0;
316 +
    store w32 4 %70 4;
317 +
    blit %68 %70 8;
318 +
    load w32 %72 %69 0;
319 +
    br.eq w32 %72 1 @and#then36 @and#else37;
320 +
  @assert.fail34
321 +
    unreachable;
322 +
  @assert.ok35
323 +
    reserve %76 8 4;
324 +
    blit %76 %68 8;
325 +
    load w32 %77 %76 4;
326 +
    br.eq w32 %77 4 @assert.ok40 @assert.fail39;
327 +
  @and#then36
328 +
    load w32 %73 %69 4;
329 +
    eq w32 %74 %73 2;
330 +
    jmp @and#end38(%74);
331 +
  @and#else37
332 +
    jmp @and#end38(0);
333 +
  @and#end38(w8 %71)
334 +
    br.ne w32 %71 0 @assert.ok35 @assert.fail34;
335 +
  @assert.fail39
336 +
    unreachable;
337 +
  @assert.ok40
338 +
    reserve %78 8 4;
339 +
    blit %78 %68 8;
340 +
    reserve %79 8 4;
341 +
    blit %79 %78 8;
342 +
    call w32 %80 $"regions.cell.pointer::replace"(%79, %68);
343 +
    br.eq w32 %80 3 @assert.ok42 @assert.fail41;
344 +
  @assert.fail41
345 +
    unreachable;
346 +
  @assert.ok42
347 +
    reserve %81 8 4;
348 +
    blit %81 %68 8;
349 +
    load w32 %82 %81 0;
350 +
    br.eq w32 %82 5 @assert.ok44 @assert.fail43;
351 +
  @assert.fail43
352 +
    unreachable;
353 +
  @assert.ok44
354 +
    load w32 %85 %1 0;
355 +
    load w32 %87 %25 0;
356 +
    add w32 %88 %85 %87;
357 +
    ret %88;
358 +
}
test/tests/regions.cell.recursive.rad added +29 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
/// Node with a link through shared mutable storage.
7 +
union Node: 'r + Copy {
8 +
    End,
9 +
    Link(&'r cell Node 'r),
10 +
}
11 +
12 +
@default unsafe fn main() -> u32 {
13 +
    static DATA: [u8; 256] = [0; 256];
14 +
    let mut arena = alloc::new(&mut DATA[..]);
15 +
    use arena as graph in {
16 +
        let initial = try! graph.new(Node 'graph::End);
17 +
        let node = initial as &'graph cell Node 'graph;
18 +
        set *node = Node 'graph::Link(node);
19 +
        let snapshot = *node;
20 +
        match snapshot {
21 +
            case Node 'graph::Link(alias) => set *alias = Node 'graph::End,
22 +
            case Node 'graph::End => panic,
23 +
        }
24 +
        match *node {
25 +
            case Node 'graph::End => return 42,
26 +
            case Node 'graph::Link(_) => panic,
27 +
        }
28 +
    }
29 +
}
test/tests/regions.cell.recursive.ril added +79 -0
1 +
data mut $"regions.cell.recursive::regions.cell.recursive::main$nominal$DATA" align 1 {
2 +
    w8 0 * 256;
3 +
}
4 +
5 +
fn w32 $"regions.cell.recursive::main"() {
6 +
  @entry0
7 +
    copy %0 $"regions.cell.recursive::regions.cell.recursive::main$nominal$DATA";
8 +
    reserve %1 16 8;
9 +
    store w64 %0 %1 0;
10 +
    store w32 256 %1 8;
11 +
    store w32 256 %1 12;
12 +
    reserve %2 24 8;
13 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
14 +
    reserve %4 16 8;
15 +
    store w64 %3 %4 0;
16 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
17 +
    load w64 %5 %4 0;
18 +
    load w64 %6 %4 8;
19 +
    load w64 %7 %6 0;
20 +
    reserve %8 16 8;
21 +
    store w8 0 %8 0;
22 +
    reserve %9 16 8;
23 +
    blit %9 %8 16;
24 +
    reserve %10 16 8;
25 +
    call w64 %11 %7(%10, %5, 16, 8);
26 +
    load w64 %12 %11 0;
27 +
    reserve %13 8 8;
28 +
    br.ne w32 %12 0 @err2 @ok1;
29 +
  @ok1
30 +
    load w64 %14 %11 8;
31 +
    blit %14 %9 16;
32 +
    load w64 %15 %11 8;
33 +
    store w64 %15 %13 0;
34 +
    jmp @merge3;
35 +
  @err2
36 +
    unreachable;
37 +
  @merge3
38 +
    load w64 %16 %13 0;
39 +
    reserve %17 8 8;
40 +
    store w64 %16 %17 0;
41 +
    reserve %18 16 8;
42 +
    store w8 1 %18 0;
43 +
    add w64 %19 %18 8;
44 +
    blit %19 %17 8;
45 +
    blit %16 %18 16;
46 +
    reserve %20 16 8;
47 +
    blit %20 %16 16;
48 +
    reserve %21 16 8;
49 +
    blit %21 %20 16;
50 +
    jmp @arm4;
51 +
  @arm4
52 +
    load w8 %22 %21 0;
53 +
    br.eq w8 %22 1 @case5 @arm6;
54 +
  @case5
55 +
    load w64 %23 %21 8;
56 +
    reserve %24 16 8;
57 +
    store w8 0 %24 0;
58 +
    blit %23 %24 16;
59 +
    jmp @merge7;
60 +
  @arm6
61 +
    jmp @case8;
62 +
  @merge7
63 +
    reserve %25 16 8;
64 +
    blit %25 %16 16;
65 +
    reserve %26 16 8;
66 +
    blit %26 %25 16;
67 +
    jmp @arm10;
68 +
  @case8
69 +
    unreachable;
70 +
  @arm10
71 +
    load w8 %27 %26 0;
72 +
    br.eq w8 %27 0 @case11 @arm12;
73 +
  @case11
74 +
    ret 42;
75 +
  @arm12
76 +
    jmp @case13;
77 +
  @case13
78 +
    unreachable;
79 +
}
test/tests/regions.compiler.bitset.rad added +267 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
//! Bitset utilities for register tracking.
5 +
//!
6 +
//! Provides efficient bit-level set operations for tracking live registers
7 +
//! during liveness analysis and register allocation.
8 +
9 +
use std::lang::alloc;
10 +
11 +
/// Return the minimum of two 32-bit values.
12 +
fn min(a: u32, b: u32) -> u32 {
13 +
    if a < b {
14 +
        return a;
15 +
    }
16 +
    return b;
17 +
}
18 +
19 +
/// Calculate the number of 32-bit words needed to store `n` bits.
20 +
fn wordsFor(n: u32) -> u32 {
21 +
    return (n + 31) / 32;
22 +
}
23 +
24 +
/// A fixed-size bitset backed by an array of 32-bit words.
25 +
record Bitset: 'bits {
26 +
    /// Backing words. The storage must outlive the bitset and its iterators.
27 +
    bits: &'bits mut [u32],
28 +
    /// Number of bits this bitset can hold.
29 +
    len: u32,
30 +
}
31 +
32 +
/// Create a new bitset backed by the given zero-initialized storage.
33 +
/// The storage must outlive the bitset and its iterators.
34 +
fn new 'bits (bits: &'bits mut [u32]) -> Bitset 'bits {
35 +
    let len = bits.len * 32;
36 +
    return Bitset { bits: bits, len };
37 +
}
38 +
39 +
/// Create a new bitset backed by the given storage, zeroing it first.
40 +
/// The storage must outlive the bitset and its iterators.
41 +
fn init 'bits (bits: &'bits mut [u32]) -> Bitset 'bits {
42 +
    for i in 0..bits.len {
43 +
        set bits[i] = 0;
44 +
    }
45 +
    return new(bits);
46 +
}
47 +
48 +
/// Create a bitset from arena allocation.
49 +
fn allocate 'bits (allocation: &Session 'bits, len: u32) -> Bitset 'bits throws (alloc::AllocError) {
50 +
    let bits = try allocation.fill(0 as u32, wordsFor(len));
51 +
    return new(bits);
52 +
}
53 +
54 +
/// Set bit `n` in the bitset.
55 +
fn put 'bits (bs: &mut Bitset 'bits, n: u32) {
56 +
    if n >= bs.len {
57 +
        return;
58 +
    }
59 +
    let word = n / 32;
60 +
    let b = n % 32;
61 +
62 +
    set bs.bits[word] |= (1 << b);
63 +
}
64 +
65 +
/// Clear bit `n` in the bitset.
66 +
fn clear 'bits (bs: &mut Bitset 'bits, n: u32) {
67 +
    if n >= bs.len {
68 +
        return;
69 +
    }
70 +
    let word = n / 32;
71 +
    let b = n % 32;
72 +
73 +
    set bs.bits[word] &= ~(1 << b);
74 +
}
75 +
76 +
/// Check if bit `n` is set.
77 +
fn contains 'bits (bs: &Bitset 'bits, n: u32) -> bool {
78 +
    if n >= bs.len {
79 +
        return false;
80 +
    }
81 +
    let word = n / 32;
82 +
    let b = n % 32;
83 +
84 +
    return (bs.bits[word] & (1 << b)) <> 0;
85 +
}
86 +
87 +
/// Count the number of set bits.
88 +
fn count 'bits (bs: &Bitset 'bits) -> u32 {
89 +
    let mut total: u32 = 0;
90 +
    let numWords = bs.bits.len;
91 +
    for i in 0..numWords {
92 +
        let word = bs.bits[i];
93 +
        if word <> 0 {
94 +
            set total += popCount(word);
95 +
        }
96 +
    }
97 +
    return total;
98 +
}
99 +
100 +
/// Population count for a 32-bit word.
101 +
fn popCount(x: u32) -> u32 {
102 +
    let mut n = x;
103 +
    set n -= ((n >> 1) & 0x55555555);
104 +
    set n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
105 +
    set n = (n + (n >> 4)) & 0x0F0F0F0F;
106 +
    set n += (n >> 8);
107 +
    set n += (n >> 16);
108 +
109 +
    return n & 0x3F;
110 +
}
111 +
112 +
/// Union: `dst = dst | src`.
113 +
fn union_ 'bits (dst: &mut Bitset 'bits, src: &Bitset 'bits) {
114 +
    let numWords = dst.bits.len;
115 +
    let srcWords = src.bits.len;
116 +
    let minWords = min(numWords, srcWords);
117 +
    for i in 0..minWords {
118 +
        set dst.bits[i] |= src.bits[i];
119 +
    }
120 +
}
121 +
122 +
/// Subtract: `dst = dst - src`.
123 +
fn subtract 'bits (dst: &mut Bitset 'bits, src: &Bitset 'bits) {
124 +
    let numWords = dst.bits.len;
125 +
    let srcWords = src.bits.len;
126 +
    let minWords = min(numWords, srcWords);
127 +
    for i in 0..minWords {
128 +
        set dst.bits[i] &= ~src.bits[i];
129 +
    }
130 +
}
131 +
132 +
/// Check if two bitsets are equal.
133 +
fn eq 'bits (a: &Bitset 'bits, b: &Bitset 'bits) -> bool {
134 +
    let numWordsA = a.bits.len;
135 +
    let numWordsB = b.bits.len;
136 +
    let minWords = min(numWordsA, numWordsB);
137 +
138 +
    for i in 0..minWords {
139 +
        if a.bits[i] <> b.bits[i] {
140 +
            return false;
141 +
        }
142 +
    }
143 +
    for i in minWords..numWordsA {
144 +
        if a.bits[i] <> 0 {
145 +
            return false;
146 +
        }
147 +
    }
148 +
    for i in minWords..numWordsB {
149 +
        if b.bits[i] <> 0 {
150 +
            return false;
151 +
        }
152 +
    }
153 +
    return true;
154 +
}
155 +
156 +
/// Copy bits from source to destination.
157 +
fn copy 'bits (dst: &mut Bitset 'bits, src: &Bitset 'bits) {
158 +
    let numWords = dst.bits.len;
159 +
    let srcWords = src.bits.len;
160 +
    let minWords = min(numWords, srcWords);
161 +
162 +
    for i in 0..minWords {
163 +
        set dst.bits[i] = src.bits[i];
164 +
    }
165 +
    // Clear remaining words if destination is larger.
166 +
    for i in minWords..numWords {
167 +
        set dst.bits[i] = 0;
168 +
    }
169 +
}
170 +
171 +
/// Clear all bits.
172 +
fn clearAll 'bits (bs: &mut Bitset 'bits) {
173 +
    let numWords = bs.bits.len;
174 +
    for i in 0..numWords {
175 +
        set bs.bits[i] = 0;
176 +
    }
177 +
}
178 +
179 +
/// Iterator state for iterating set bits.
180 +
record BitIter: Copy {
181 +
    /// Current word index.
182 +
    wordIdx: u32,
183 +
    /// Remaining bits in the current word (visited bits cleared).
184 +
    remaining: u32,
185 +
}
186 +
187 +
/// Create an iterator over set bits.
188 +
/// The cursor retains the first word mask and its position.
189 +
fn iter 'bits (bs: &Bitset 'bits) -> BitIter {
190 +
    let remaining = bs.bits[0] if bs.len > 0 else 0;
191 +
    return BitIter { wordIdx: 0, remaining };
192 +
}
193 +
194 +
/// Get the next set bit, or nil if none remain.
195 +
fn iterNext 'bits (it: &mut BitIter, bs: &Bitset 'bits) -> ?u32 {
196 +
    let numWords = bs.bits.len;
197 +
    // Skip to next non-zero word.
198 +
    while it.remaining == 0 {
199 +
        set it.wordIdx += 1;
200 +
        if it.wordIdx >= numWords {
201 +
            return nil;
202 +
        }
203 +
        set it.remaining = bs.bits[it.wordIdx];
204 +
    }
205 +
    // Find lowest set bit position using de Bruijn sequence.
206 +
    let b = ctz(it.remaining);
207 +
    let n = it.wordIdx * 32 + b;
208 +
    if n >= bs.len {
209 +
        return nil;
210 +
    }
211 +
    // Clear the lowest set bit.
212 +
    set it.remaining &= it.remaining - 1;
213 +
214 +
    return n;
215 +
}
216 +
217 +
/// Count trailing zeros in a 32-bit value.
218 +
/// Returns the bit position of the lowest set bit (0-31).
219 +
/// Behavior is undefined if `x` is 0.
220 +
fn ctz(x: u32) -> u32 {
221 +
    // De Bruijn sequence for 32-bit CTZ.
222 +
    constant DEBRUIJN: u32 = 0x077CB531;
223 +
    constant TABLE: [u8; 32] = [
224 +
         0,  1, 28,  2, 29, 14, 24,  3, 30, 22, 20, 15, 25, 17,  4,  8,
225 +
        31, 27, 13, 23, 21, 19, 16,  7, 26, 12, 18,  6, 11,  5, 10,  9,
226 +
    ];
227 +
    // Isolate lowest set bit, multiply by de Bruijn constant, look up.
228 +
    let isolated = x & (~x + 1);
229 +
230 +
    return TABLE[(isolated * DEBRUIJN) >> 27] as u32;
231 +
}
232 +
233 +
@default fn main() -> u32 {
234 +
    static DATA: [u8; 256] = [0; 256];
235 +
    let mut arena = alloc::new(&mut DATA[..]);
236 +
    use arena as words in {
237 +
        let mut first = try! allocate(&words, 96);
238 +
        let mut second = try! allocate(&words, 96);
239 +
        put(&mut first, 1);
240 +
        put(&mut first, 41);
241 +
        put(&mut second, 41);
242 +
        put(&mut second, 65);
243 +
        union_(&mut first, &second);
244 +
        assert count(&first) == 3;
245 +
        subtract(&mut first, &second);
246 +
        assert count(&first) == 1 and contains(&first, 1);
247 +
        copy(&mut first, &second);
248 +
        assert eq(&first, &second);
249 +
        {
250 +
            let mut cursor = iter(&first);
251 +
            assert iterNext(&mut cursor, &first) == 41;
252 +
            clear(&mut first, 41);
253 +
            assert iterNext(&mut cursor, &first) == 65;
254 +
            assert iterNext(&mut cursor, &first) == nil;
255 +
        }
256 +
        clearAll(&mut first);
257 +
        assert count(&first) == 0;
258 +
        put(&mut first, 42);
259 +
        clear(&mut second, 65);
260 +
        assert count(&second) == 1;
261 +
        {
262 +
            let mut cursor = iter(&first);
263 +
            let result = iterNext(&mut cursor, &first) else return 0;
264 +
            return result;
265 +
        }
266 +
    }
267 +
}
test/tests/regions.compiler.bitset.ril added +745 -0
1 +
data $"regions.compiler.bitset::regions.compiler.bitset::ctz$nominal$DEBRUIJN" align 4 {
2 +
    w32 125613361;
3 +
}
4 +
5 +
data $"regions.compiler.bitset::regions.compiler.bitset::ctz$nominal$TABLE" align 1 {
6 +
    w8 0;
7 +
    w8 1;
8 +
    w8 28;
9 +
    w8 2;
10 +
    w8 29;
11 +
    w8 14;
12 +
    w8 24;
13 +
    w8 3;
14 +
    w8 30;
15 +
    w8 22;
16 +
    w8 20;
17 +
    w8 15;
18 +
    w8 25;
19 +
    w8 17;
20 +
    w8 4;
21 +
    w8 8;
22 +
    w8 31;
23 +
    w8 27;
24 +
    w8 13;
25 +
    w8 23;
26 +
    w8 21;
27 +
    w8 19;
28 +
    w8 16;
29 +
    w8 7;
30 +
    w8 26;
31 +
    w8 12;
32 +
    w8 18;
33 +
    w8 6;
34 +
    w8 11;
35 +
    w8 5;
36 +
    w8 10;
37 +
    w8 9;
38 +
}
39 +
40 +
data mut $"regions.compiler.bitset::regions.compiler.bitset::main$nominal$DATA" align 1 {
41 +
    w8 0 * 256;
42 +
}
43 +
44 +
fn w32 $"regions.compiler.bitset::min"(w32 %0, w32 %1) {
45 +
  @entry0
46 +
    br.ult w32 %0 %1 @then1 @merge2;
47 +
  @then1
48 +
    ret %0;
49 +
  @merge2
50 +
    ret %1;
51 +
}
52 +
53 +
fn w32 $"regions.compiler.bitset::wordsFor"(w32 %0) {
54 +
  @entry0
55 +
    add w32 %1 %0 31;
56 +
    udiv w32 %2 %1 32;
57 +
    ret %2;
58 +
}
59 +
60 +
fn w64 $"regions.compiler.bitset::new"(w64 %0, w64 %1) {
61 +
  @entry0
62 +
    load w32 %2 %1 8;
63 +
    mul w32 %3 %2 32;
64 +
    reserve %4 24 8;
65 +
    blit %4 %1 16;
66 +
    store w32 %3 %4 16;
67 +
    blit %0 %4 24;
68 +
    ret %0;
69 +
}
70 +
71 +
fn w64 $"regions.compiler.bitset::init"(w64 %0, w64 %1) {
72 +
  @entry0
73 +
    load w32 %2 %1 8;
74 +
    jmp @loop1(0, %1);
75 +
  @loop1(w32 %3, w64 %4)
76 +
    br.ult w32 %3 %2 @body2 @merge3;
77 +
  @body2
78 +
    load w32 %5 %4 8;
79 +
    br.ult w32 %3 %5 @guard#pass4 @guard#trap5;
80 +
  @merge3
81 +
    reserve %10 24 8;
82 +
    call w64 %11 $"regions.compiler.bitset::new"(%10, %4);
83 +
    blit %0 %11 24;
84 +
    ret %0;
85 +
  @guard#pass4
86 +
    load w64 %6 %4 0;
87 +
    mul w64 %7 %3 4;
88 +
    add w64 %8 %6 %7;
89 +
    store w32 0 %8 0;
90 +
    add w32 %9 %3 1;
91 +
    jmp @loop1(%9, %4);
92 +
  @guard#trap5
93 +
    ebreak;
94 +
    unreachable;
95 +
}
96 +
97 +
fn w64 $"regions.compiler.bitset::allocate"(w64 %0, w64 %1, w32 %2) {
98 +
  @entry0
99 +
    load w64 %3 %1 0;
100 +
    load w64 %4 %1 8;
101 +
    load w64 %5 %4 8;
102 +
    zext w32 %6 0;
103 +
    call w32 %7 $"regions.compiler.bitset::wordsFor"(%2);
104 +
    reserve %8 24 8;
105 +
    call w64 %9 %5(%8, %3, 4, 4, %7);
106 +
    load w64 %10 %9 0;
107 +
    reserve %11 16 8;
108 +
    br.ne w32 %10 0 @err2 @ok1;
109 +
  @ok1
110 +
    load w64 %12 %9 8;
111 +
    jmp @fill3(0);
112 +
  @err2
113 +
    reserve %18 32 8;
114 +
    store w64 %10 %18 0;
115 +
    add w64 %19 %9 8;
116 +
    add w64 %20 %18 8;
117 +
    blit %20 %19 1;
118 +
    blit %0 %18 32;
119 +
    ret %0;
120 +
  @fill3(w32 %13)
121 +
    br.ult w32 %13 %7 @fill4 @fill5;
122 +
  @fill4
123 +
    mul w64 %14 %13 4;
124 +
    add w64 %15 %12 %14;
125 +
    store w32 %6 %15 0;
126 +
    add w32 %16 %13 1;
127 +
    jmp @fill3(%16);
128 +
  @fill5
129 +
    add w64 %17 %9 8;
130 +
    blit %11 %17 16;
131 +
    jmp @merge6;
132 +
  @merge6
133 +
    reserve %21 24 8;
134 +
    call w64 %22 $"regions.compiler.bitset::new"(%21, %11);
135 +
    reserve %23 32 8;
136 +
    store w64 0 %23 0;
137 +
    add w64 %24 %23 8;
138 +
    blit %24 %22 24;
139 +
    blit %0 %23 32;
140 +
    ret %0;
141 +
}
142 +
143 +
fn w64 $"regions.compiler.bitset::put"(w64 %0, w32 %1) {
144 +
  @entry0
145 +
    load w32 %2 %0 16;
146 +
    br.ult w32 %1 %2 @merge2 @then1;
147 +
  @then1
148 +
    ret undefined;
149 +
  @merge2
150 +
    udiv w32 %3 %1 32;
151 +
    urem w32 %4 %1 32;
152 +
    load w32 %5 %0 8;
153 +
    br.ult w32 %3 %5 @guard#pass3 @guard#trap4;
154 +
  @guard#pass3
155 +
    load w64 %6 %0 0;
156 +
    mul w64 %7 %3 4;
157 +
    add w64 %8 %6 %7;
158 +
    load w32 %9 %8 0;
159 +
    shl w32 %10 1 %4;
160 +
    or w32 %11 %9 %10;
161 +
    store w32 %11 %8 0;
162 +
    ret;
163 +
  @guard#trap4
164 +
    ebreak;
165 +
    unreachable;
166 +
}
167 +
168 +
fn w64 $"regions.compiler.bitset::clear"(w64 %0, w32 %1) {
169 +
  @entry0
170 +
    load w32 %2 %0 16;
171 +
    br.ult w32 %1 %2 @merge2 @then1;
172 +
  @then1
173 +
    ret undefined;
174 +
  @merge2
175 +
    udiv w32 %3 %1 32;
176 +
    urem w32 %4 %1 32;
177 +
    load w32 %5 %0 8;
178 +
    br.ult w32 %3 %5 @guard#pass3 @guard#trap4;
179 +
  @guard#pass3
180 +
    load w64 %6 %0 0;
181 +
    mul w64 %7 %3 4;
182 +
    add w64 %8 %6 %7;
183 +
    load w32 %9 %8 0;
184 +
    shl w32 %10 1 %4;
185 +
    not w32 %11 %10;
186 +
    and w32 %12 %9 %11;
187 +
    store w32 %12 %8 0;
188 +
    ret;
189 +
  @guard#trap4
190 +
    ebreak;
191 +
    unreachable;
192 +
}
193 +
194 +
fn w8 $"regions.compiler.bitset::contains"(w64 %0, w32 %1) {
195 +
  @entry0
196 +
    load w32 %2 %0 16;
197 +
    br.ult w32 %1 %2 @merge2 @then1;
198 +
  @then1
199 +
    ret 0;
200 +
  @merge2
201 +
    udiv w32 %3 %1 32;
202 +
    urem w32 %4 %1 32;
203 +
    load w32 %5 %0 8;
204 +
    br.ult w32 %3 %5 @guard#pass3 @guard#trap4;
205 +
  @guard#pass3
206 +
    load w64 %6 %0 0;
207 +
    mul w64 %7 %3 4;
208 +
    add w64 %8 %6 %7;
209 +
    load w32 %9 %8 0;
210 +
    shl w32 %10 1 %4;
211 +
    and w32 %11 %9 %10;
212 +
    ne w32 %12 %11 0;
213 +
    ret %12;
214 +
  @guard#trap4
215 +
    ebreak;
216 +
    unreachable;
217 +
}
218 +
219 +
fn w32 $"regions.compiler.bitset::count"(w64 %0) {
220 +
  @entry0
221 +
    load w32 %1 %0 8;
222 +
    jmp @loop1(0, %0, 0);
223 +
  @loop1(w32 %2, w64 %3, w32 %9)
224 +
    br.ult w32 %2 %1 @body2 @merge3;
225 +
  @body2
226 +
    load w32 %4 %3 8;
227 +
    br.ult w32 %2 %4 @guard#pass4 @guard#trap5;
228 +
  @merge3
229 +
    ret %9;
230 +
  @guard#pass4
231 +
    load w64 %5 %3 0;
232 +
    mul w64 %6 %2 4;
233 +
    add w64 %7 %5 %6;
234 +
    load w32 %8 %7 0;
235 +
    br.ne w32 %8 0 @then6 @merge7(%9);
236 +
  @guard#trap5
237 +
    ebreak;
238 +
    unreachable;
239 +
  @then6
240 +
    call w32 %10 $"regions.compiler.bitset::popCount"(%8);
241 +
    add w32 %11 %9 %10;
242 +
    jmp @merge7(%11);
243 +
  @merge7(w32 %15)
244 +
    add w32 %13 %2 1;
245 +
    jmp @loop1(%13, %3, %15);
246 +
}
247 +
248 +
fn w32 $"regions.compiler.bitset::popCount"(w32 %0) {
249 +
  @entry0
250 +
    ushr w32 %1 %0 1;
251 +
    and w32 %2 %1 1431655765;
252 +
    sub w32 %3 %0 %2;
253 +
    and w32 %4 %3 858993459;
254 +
    ushr w32 %5 %3 2;
255 +
    and w32 %6 %5 858993459;
256 +
    add w32 %7 %4 %6;
257 +
    ushr w32 %8 %7 4;
258 +
    add w32 %9 %7 %8;
259 +
    and w32 %10 %9 252645135;
260 +
    ushr w32 %11 %10 8;
261 +
    add w32 %12 %10 %11;
262 +
    ushr w32 %13 %12 16;
263 +
    add w32 %14 %12 %13;
264 +
    and w32 %15 %14 63;
265 +
    ret %15;
266 +
}
267 +
268 +
fn w64 $"regions.compiler.bitset::union_"(w64 %0, w64 %1) {
269 +
  @entry0
270 +
    load w32 %2 %0 8;
271 +
    load w32 %3 %1 8;
272 +
    call w32 %4 $"regions.compiler.bitset::min"(%2, %3);
273 +
    jmp @loop1(0, %0, %1);
274 +
  @loop1(w32 %5, w64 %6, w64 %12)
275 +
    br.ult w32 %5 %4 @body2 @merge3;
276 +
  @body2
277 +
    load w32 %7 %6 8;
278 +
    br.ult w32 %5 %7 @guard#pass4 @guard#trap5;
279 +
  @merge3
280 +
    ret;
281 +
  @guard#pass4
282 +
    load w64 %8 %6 0;
283 +
    mul w64 %9 %5 4;
284 +
    add w64 %10 %8 %9;
285 +
    load w32 %11 %10 0;
286 +
    load w32 %13 %12 8;
287 +
    br.ult w32 %5 %13 @guard#pass6 @guard#trap7;
288 +
  @guard#trap5
289 +
    ebreak;
290 +
    unreachable;
291 +
  @guard#pass6
292 +
    load w64 %14 %12 0;
293 +
    mul w64 %15 %5 4;
294 +
    add w64 %16 %14 %15;
295 +
    load w32 %17 %16 0;
296 +
    or w32 %18 %11 %17;
297 +
    store w32 %18 %10 0;
298 +
    add w32 %19 %5 1;
299 +
    jmp @loop1(%19, %6, %12);
300 +
  @guard#trap7
301 +
    ebreak;
302 +
    unreachable;
303 +
}
304 +
305 +
fn w64 $"regions.compiler.bitset::subtract"(w64 %0, w64 %1) {
306 +
  @entry0
307 +
    load w32 %2 %0 8;
308 +
    load w32 %3 %1 8;
309 +
    call w32 %4 $"regions.compiler.bitset::min"(%2, %3);
310 +
    jmp @loop1(0, %0, %1);
311 +
  @loop1(w32 %5, w64 %6, w64 %12)
312 +
    br.ult w32 %5 %4 @body2 @merge3;
313 +
  @body2
314 +
    load w32 %7 %6 8;
315 +
    br.ult w32 %5 %7 @guard#pass4 @guard#trap5;
316 +
  @merge3
317 +
    ret;
318 +
  @guard#pass4
319 +
    load w64 %8 %6 0;
320 +
    mul w64 %9 %5 4;
321 +
    add w64 %10 %8 %9;
322 +
    load w32 %11 %10 0;
323 +
    load w32 %13 %12 8;
324 +
    br.ult w32 %5 %13 @guard#pass6 @guard#trap7;
325 +
  @guard#trap5
326 +
    ebreak;
327 +
    unreachable;
328 +
  @guard#pass6
329 +
    load w64 %14 %12 0;
330 +
    mul w64 %15 %5 4;
331 +
    add w64 %16 %14 %15;
332 +
    load w32 %17 %16 0;
333 +
    not w32 %18 %17;
334 +
    and w32 %19 %11 %18;
335 +
    store w32 %19 %10 0;
336 +
    add w32 %20 %5 1;
337 +
    jmp @loop1(%20, %6, %12);
338 +
  @guard#trap7
339 +
    ebreak;
340 +
    unreachable;
341 +
}
342 +
343 +
fn w8 $"regions.compiler.bitset::eq"(w64 %0, w64 %1) {
344 +
  @entry0
345 +
    load w32 %2 %0 8;
346 +
    load w32 %3 %1 8;
347 +
    call w32 %4 $"regions.compiler.bitset::min"(%2, %3);
348 +
    jmp @loop1(0, %0, %1);
349 +
  @loop1(w32 %5, w64 %6, w64 %12)
350 +
    br.ult w32 %5 %4 @body2 @merge3;
351 +
  @body2
352 +
    load w32 %7 %6 8;
353 +
    br.ult w32 %5 %7 @guard#pass6 @guard#trap7;
354 +
  @merge3
355 +
    jmp @loop10(%4, %6);
356 +
  @then4
357 +
    ret 0;
358 +
  @merge5
359 +
    add w32 %18 %5 1;
360 +
    jmp @loop1(%18, %6, %12);
361 +
  @guard#pass6
362 +
    load w64 %8 %6 0;
363 +
    mul w64 %9 %5 4;
364 +
    add w64 %10 %8 %9;
365 +
    load w32 %11 %10 0;
366 +
    load w32 %13 %12 8;
367 +
    br.ult w32 %5 %13 @guard#pass8 @guard#trap9;
368 +
  @guard#trap7
369 +
    ebreak;
370 +
    unreachable;
371 +
  @guard#pass8
372 +
    load w64 %14 %12 0;
373 +
    mul w64 %15 %5 4;
374 +
    add w64 %16 %14 %15;
375 +
    load w32 %17 %16 0;
376 +
    br.ne w32 %11 %17 @then4 @merge5;
377 +
  @guard#trap9
378 +
    ebreak;
379 +
    unreachable;
380 +
  @loop10(w32 %21, w64 %22)
381 +
    br.ult w32 %21 %2 @body11 @merge12;
382 +
  @body11
383 +
    load w32 %23 %22 8;
384 +
    br.ult w32 %21 %23 @guard#pass15 @guard#trap16;
385 +
  @merge12
386 +
    jmp @loop17(%4, %12);
387 +
  @then13
388 +
    ret 0;
389 +
  @merge14
390 +
    add w32 %28 %21 1;
391 +
    jmp @loop10(%28, %22);
392 +
  @guard#pass15
393 +
    load w64 %24 %22 0;
394 +
    mul w64 %25 %21 4;
395 +
    add w64 %26 %24 %25;
396 +
    load w32 %27 %26 0;
397 +
    br.ne w32 %27 0 @then13 @merge14;
398 +
  @guard#trap16
399 +
    ebreak;
400 +
    unreachable;
401 +
  @loop17(w32 %32, w64 %33)
402 +
    br.ult w32 %32 %3 @body18 @merge19;
403 +
  @body18
404 +
    load w32 %34 %33 8;
405 +
    br.ult w32 %32 %34 @guard#pass22 @guard#trap23;
406 +
  @merge19
407 +
    ret 1;
408 +
  @then20
409 +
    ret 0;
410 +
  @merge21
411 +
    add w32 %39 %32 1;
412 +
    jmp @loop17(%39, %33);
413 +
  @guard#pass22
414 +
    load w64 %35 %33 0;
415 +
    mul w64 %36 %32 4;
416 +
    add w64 %37 %35 %36;
417 +
    load w32 %38 %37 0;
418 +
    br.ne w32 %38 0 @then20 @merge21;
419 +
  @guard#trap23
420 +
    ebreak;
421 +
    unreachable;
422 +
}
423 +
424 +
fn w64 $"regions.compiler.bitset::copy"(w64 %0, w64 %1) {
425 +
  @entry0
426 +
    load w32 %2 %0 8;
427 +
    load w32 %3 %1 8;
428 +
    call w32 %4 $"regions.compiler.bitset::min"(%2, %3);
429 +
    jmp @loop1(0, %1, %0);
430 +
  @loop1(w32 %5, w64 %6, w64 %12)
431 +
    br.ult w32 %5 %4 @body2 @merge3;
432 +
  @body2
433 +
    load w32 %7 %6 8;
434 +
    br.ult w32 %5 %7 @guard#pass4 @guard#trap5;
435 +
  @merge3
436 +
    jmp @loop8(%4, %12);
437 +
  @guard#pass4
438 +
    load w64 %8 %6 0;
439 +
    mul w64 %9 %5 4;
440 +
    add w64 %10 %8 %9;
441 +
    load w32 %11 %10 0;
442 +
    load w32 %13 %12 8;
443 +
    br.ult w32 %5 %13 @guard#pass6 @guard#trap7;
444 +
  @guard#trap5
445 +
    ebreak;
446 +
    unreachable;
447 +
  @guard#pass6
448 +
    load w64 %14 %12 0;
449 +
    mul w64 %15 %5 4;
450 +
    add w64 %16 %14 %15;
451 +
    store w32 %11 %16 0;
452 +
    add w32 %17 %5 1;
453 +
    jmp @loop1(%17, %6, %12);
454 +
  @guard#trap7
455 +
    ebreak;
456 +
    unreachable;
457 +
  @loop8(w32 %20, w64 %21)
458 +
    br.ult w32 %20 %2 @body9 @merge10;
459 +
  @body9
460 +
    load w32 %22 %21 8;
461 +
    br.ult w32 %20 %22 @guard#pass11 @guard#trap12;
462 +
  @merge10
463 +
    ret;
464 +
  @guard#pass11
465 +
    load w64 %23 %21 0;
466 +
    mul w64 %24 %20 4;
467 +
    add w64 %25 %23 %24;
468 +
    store w32 0 %25 0;
469 +
    add w32 %26 %20 1;
470 +
    jmp @loop8(%26, %21);
471 +
  @guard#trap12
472 +
    ebreak;
473 +
    unreachable;
474 +
}
475 +
476 +
fn w64 $"regions.compiler.bitset::clearAll"(w64 %0) {
477 +
  @entry0
478 +
    load w32 %1 %0 8;
479 +
    jmp @loop1(0, %0);
480 +
  @loop1(w32 %2, w64 %3)
481 +
    br.ult w32 %2 %1 @body2 @merge3;
482 +
  @body2
483 +
    load w32 %4 %3 8;
484 +
    br.ult w32 %2 %4 @guard#pass4 @guard#trap5;
485 +
  @merge3
486 +
    ret;
487 +
  @guard#pass4
488 +
    load w64 %5 %3 0;
489 +
    mul w64 %6 %2 4;
490 +
    add w64 %7 %5 %6;
491 +
    store w32 0 %7 0;
492 +
    add w32 %8 %2 1;
493 +
    jmp @loop1(%8, %3);
494 +
  @guard#trap5
495 +
    ebreak;
496 +
    unreachable;
497 +
}
498 +
499 +
fn w64 $"regions.compiler.bitset::iter"(w64 %0) {
500 +
  @entry0
501 +
    load w32 %1 %0 16;
502 +
    br.ult w32 0 %1 @cond#then1 @cond#else2;
503 +
  @cond#then1
504 +
    load w32 %3 %0 8;
505 +
    br.ult w32 0 %3 @guard#pass4 @guard#trap5;
506 +
  @cond#else2
507 +
    jmp @cond#merge3(0);
508 +
  @cond#merge3(w32 %2)
509 +
    reserve %6 8 4;
510 +
    store w32 0 %6 0;
511 +
    store w32 %2 %6 4;
512 +
    reserve %7 8 8;
513 +
    store w64 0 %7 0;
514 +
    blit %7 %6 8;
515 +
    load w64 %8 %7 0;
516 +
    ret %8;
517 +
  @guard#pass4
518 +
    load w64 %4 %0 0;
519 +
    load w32 %5 %4 0;
520 +
    jmp @cond#merge3(%5);
521 +
  @guard#trap5
522 +
    ebreak;
523 +
    unreachable;
524 +
}
525 +
526 +
fn w64 $"regions.compiler.bitset::iterNext"(w64 %0, w64 %1, w64 %2) {
527 +
  @entry0
528 +
    load w32 %3 %2 8;
529 +
    jmp @while1(%1, %3, %2);
530 +
  @while1(w64 %4, w32 %9, w64 %11)
531 +
    load w32 %5 %4 4;
532 +
    br.eq w32 %5 0 @body2 @merge3;
533 +
  @body2
534 +
    load w32 %6 %4 0;
535 +
    add w32 %7 %6 1;
536 +
    store w32 %7 %4 0;
537 +
    load w32 %8 %4 0;
538 +
    br.ult w32 %8 %9 @merge5 @then4;
539 +
  @merge3
540 +
    load w32 %18 %4 4;
541 +
    call w32 %19 $"regions.compiler.bitset::ctz"(%18);
542 +
    load w32 %20 %4 0;
543 +
    mul w32 %21 %20 32;
544 +
    add w32 %22 %21 %19;
545 +
    load w32 %23 %11 16;
546 +
    br.ult w32 %22 %23 @merge9 @then8;
547 +
  @then4
548 +
    reserve %10 8 4;
549 +
    store w8 0 %10 0;
550 +
    blit %0 %10 8;
551 +
    ret %0;
552 +
  @merge5
553 +
    load w32 %12 %4 0;
554 +
    load w32 %13 %11 8;
555 +
    br.ult w32 %12 %13 @guard#pass6 @guard#trap7;
556 +
  @guard#pass6
557 +
    load w64 %14 %11 0;
558 +
    mul w64 %15 %12 4;
559 +
    add w64 %16 %14 %15;
560 +
    load w32 %17 %16 0;
561 +
    store w32 %17 %4 4;
562 +
    jmp @while1(%4, %9, %11);
563 +
  @guard#trap7
564 +
    ebreak;
565 +
    unreachable;
566 +
  @then8
567 +
    reserve %24 8 4;
568 +
    store w8 0 %24 0;
569 +
    blit %0 %24 8;
570 +
    ret %0;
571 +
  @merge9
572 +
    load w32 %25 %4 4;
573 +
    load w32 %26 %4 4;
574 +
    sub w32 %27 %26 1;
575 +
    and w32 %28 %25 %27;
576 +
    store w32 %28 %4 4;
577 +
    reserve %29 8 4;
578 +
    store w8 1 %29 0;
579 +
    store w32 %22 %29 4;
580 +
    blit %0 %29 8;
581 +
    ret %0;
582 +
}
583 +
584 +
fn w32 $"regions.compiler.bitset::ctz"(w32 %0) {
585 +
  @entry0
586 +
    not w32 %1 %0;
587 +
    add w32 %2 %1 1;
588 +
    and w32 %3 %0 %2;
589 +
    copy %4 $"regions.compiler.bitset::regions.compiler.bitset::ctz$nominal$TABLE";
590 +
    mul w32 %5 %3 125613361;
591 +
    ushr w32 %6 %5 27;
592 +
    br.ult w32 %6 32 @guard#pass1 @guard#trap2;
593 +
  @guard#pass1
594 +
    add w64 %7 %4 %6;
595 +
    load w8 %8 %7 0;
596 +
    zext w8 %9 %8;
597 +
    ret %9;
598 +
  @guard#trap2
599 +
    ebreak;
600 +
    unreachable;
601 +
}
602 +
603 +
fn w32 $"regions.compiler.bitset::main"() {
604 +
  @entry0
605 +
    copy %0 $"regions.compiler.bitset::regions.compiler.bitset::main$nominal$DATA";
606 +
    reserve %1 16 8;
607 +
    store w64 %0 %1 0;
608 +
    store w32 256 %1 8;
609 +
    store w32 256 %1 12;
610 +
    reserve %2 24 8;
611 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
612 +
    reserve %4 16 8;
613 +
    store w64 %3 %4 0;
614 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
615 +
    reserve %5 32 8;
616 +
    call w64 %6 $"regions.compiler.bitset::allocate"(%5, %4, 96);
617 +
    load w64 %7 %6 0;
618 +
    reserve %8 24 8;
619 +
    br.ne w32 %7 0 @err2 @ok1;
620 +
  @ok1
621 +
    add w64 %9 %6 8;
622 +
    blit %8 %9 24;
623 +
    jmp @merge3;
624 +
  @err2
625 +
    unreachable;
626 +
  @merge3
627 +
    reserve %10 32 8;
628 +
    call w64 %11 $"regions.compiler.bitset::allocate"(%10, %4, 96);
629 +
    load w64 %12 %11 0;
630 +
    reserve %13 24 8;
631 +
    br.ne w32 %12 0 @err5 @ok4;
632 +
  @ok4
633 +
    add w64 %14 %11 8;
634 +
    blit %13 %14 24;
635 +
    jmp @merge6;
636 +
  @err5
637 +
    unreachable;
638 +
  @merge6
639 +
    call w64 $"regions.compiler.bitset::put"(%8, 1);
640 +
    call w64 $"regions.compiler.bitset::put"(%8, 41);
641 +
    call w64 $"regions.compiler.bitset::put"(%13, 41);
642 +
    call w64 $"regions.compiler.bitset::put"(%13, 65);
643 +
    call w64 $"regions.compiler.bitset::union_"(%8, %13);
644 +
    call w32 %15 $"regions.compiler.bitset::count"(%8);
645 +
    br.eq w32 %15 3 @assert.ok8 @assert.fail7;
646 +
  @assert.fail7
647 +
    unreachable;
648 +
  @assert.ok8
649 +
    call w64 $"regions.compiler.bitset::subtract"(%8, %13);
650 +
    call w32 %17 $"regions.compiler.bitset::count"(%8);
651 +
    br.eq w32 %17 1 @and#then11 @and#else12;
652 +
  @assert.fail9
653 +
    unreachable;
654 +
  @assert.ok10
655 +
    call w64 $"regions.compiler.bitset::copy"(%8, %13);
656 +
    call w8 %21 $"regions.compiler.bitset::eq"(%8, %13);
657 +
    br.ne w32 %21 0 @assert.ok15 @assert.fail14;
658 +
  @and#then11
659 +
    call w8 %18 $"regions.compiler.bitset::contains"(%8, 1);
660 +
    jmp @and#end13(%18);
661 +
  @and#else12
662 +
    jmp @and#end13(0);
663 +
  @and#end13(w8 %16)
664 +
    br.ne w32 %16 0 @assert.ok10 @assert.fail9;
665 +
  @assert.fail14
666 +
    unreachable;
667 +
  @assert.ok15
668 +
    call w64 %22 $"regions.compiler.bitset::iter"(%8);
669 +
    reserve %23 8 8;
670 +
    store w64 %22 %23 0;
671 +
    reserve %24 8 4;
672 +
    call w64 %25 $"regions.compiler.bitset::iterNext"(%24, %23, %8);
673 +
    reserve %26 8 4;
674 +
    store w8 1 %26 0;
675 +
    store w32 41 %26 4;
676 +
    load w8 %27 %25 0;
677 +
    load w8 %28 %26 0;
678 +
    eq w8 %29 %27 %28;
679 +
    eq w8 %30 %27 0;
680 +
    load w32 %31 %25 4;
681 +
    load w32 %32 %26 4;
682 +
    eq w32 %33 %31 %32;
683 +
    or w32 %34 %30 %33;
684 +
    and w32 %35 %29 %34;
685 +
    br.ne w32 %35 0 @assert.ok17 @assert.fail16;
686 +
  @assert.fail16
687 +
    unreachable;
688 +
  @assert.ok17
689 +
    call w64 $"regions.compiler.bitset::clear"(%8, 41);
690 +
    reserve %36 8 4;
691 +
    call w64 %37 $"regions.compiler.bitset::iterNext"(%36, %23, %8);
692 +
    reserve %38 8 4;
693 +
    store w8 1 %38 0;
694 +
    store w32 65 %38 4;
695 +
    load w8 %39 %37 0;
696 +
    load w8 %40 %38 0;
697 +
    eq w8 %41 %39 %40;
698 +
    eq w8 %42 %39 0;
699 +
    load w32 %43 %37 4;
700 +
    load w32 %44 %38 4;
701 +
    eq w32 %45 %43 %44;
702 +
    or w32 %46 %42 %45;
703 +
    and w32 %47 %41 %46;
704 +
    br.ne w32 %47 0 @assert.ok19 @assert.fail18;
705 +
  @assert.fail18
706 +
    unreachable;
707 +
  @assert.ok19
708 +
    reserve %48 8 4;
709 +
    call w64 %49 $"regions.compiler.bitset::iterNext"(%48, %23, %8);
710 +
    load w8 %50 %49 0;
711 +
    eq w8 %51 %50 0;
712 +
    br.ne w32 %51 0 @assert.ok21 @assert.fail20;
713 +
  @assert.fail20
714 +
    unreachable;
715 +
  @assert.ok21
716 +
    call w64 $"regions.compiler.bitset::clearAll"(%8);
717 +
    call w32 %52 $"regions.compiler.bitset::count"(%8);
718 +
    br.eq w32 %52 0 @assert.ok23 @assert.fail22;
719 +
  @assert.fail22
720 +
    unreachable;
721 +
  @assert.ok23
722 +
    call w64 $"regions.compiler.bitset::put"(%8, 42);
723 +
    call w64 $"regions.compiler.bitset::clear"(%13, 65);
724 +
    call w32 %53 $"regions.compiler.bitset::count"(%13);
725 +
    br.eq w32 %53 1 @assert.ok25 @assert.fail24;
726 +
  @assert.fail24
727 +
    unreachable;
728 +
  @assert.ok25
729 +
    call w64 %54 $"regions.compiler.bitset::iter"(%8);
730 +
    reserve %55 8 8;
731 +
    store w64 %54 %55 0;
732 +
    reserve %56 8 4;
733 +
    call w64 %57 $"regions.compiler.bitset::iterNext"(%56, %55, %8);
734 +
    reserve %58 8 4;
735 +
    blit %58 %57 8;
736 +
    load w8 %59 %58 0;
737 +
    br.ne w32 %59 0 @success26 @else27;
738 +
  @success26
739 +
    load w32 %60 %58 4;
740 +
    jmp @merge28;
741 +
  @else27
742 +
    ret 0;
743 +
  @merge28
744 +
    ret %60;
745 +
}
test/tests/regions.compiler.regmap.rad added +45 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
/// Physical register number.
7 +
record Reg: Copy(u8);
8 +
9 +
/// Register mappings retained in session storage.
10 +
record RegMap: 'scratch {
11 +
    /// Virtual register numbers.
12 +
    virtRegs: &'scratch mut [u32],
13 +
    /// Physical register numbers.
14 +
    physRegs: &'scratch mut [Reg],
15 +
    /// Number of initialized mappings.
16 +
    n: u32,
17 +
}
18 +
19 +
/// Transfer a register map while retaining its session storage.
20 +
fn transfer 'r (map: RegMap 'r) -> RegMap 'r {
21 +
    return map;
22 +
}
23 +
24 +
@default unsafe fn main() -> u32 {
25 +
    static DATA: [u8; 4096] = [0; 4096];
26 +
    let mut arena = alloc::new(&mut DATA[..]);
27 +
    use arena as registers in {
28 +
        let virtual = try! registers.fill(0 as u32, 64);
29 +
        let physical = try! registers.fill(Reg(0), 64);
30 +
        let map: RegMap 'registers = RegMap {
31 +
            virtRegs: virtual, physRegs: physical, n: 0,
32 +
        };
33 +
        let mut moved = transfer(map);
34 +
        set moved.virtRegs[0] = 40;
35 +
        set moved.physRegs[0] = Reg(2);
36 +
        set moved.n = 1;
37 +
        let current: 'instruction = &mut moved where 'registers: 'instruction in {
38 +
            set current.virtRegs[0] += *current.physRegs[0] as u32;
39 +
        }
40 +
        assert moved.n == 1;
41 +
        assert moved.virtRegs[63] == 0;
42 +
        assert *moved.physRegs[63] == 0;
43 +
        return moved.virtRegs[0];
44 +
    }
45 +
}
test/tests/regions.compiler.regmap.ril added +166 -0
1 +
data mut $"regions.compiler.regmap::regions.compiler.regmap::main$nominal$DATA" align 1 {
2 +
    w8 0 * 4096;
3 +
}
4 +
5 +
fn w64 $"regions.compiler.regmap::transfer"(w64 %0, w64 %1) {
6 +
  @entry0
7 +
    blit %0 %1 40;
8 +
    ret %0;
9 +
}
10 +
11 +
fn w32 $"regions.compiler.regmap::main"() {
12 +
  @entry0
13 +
    copy %0 $"regions.compiler.regmap::regions.compiler.regmap::main$nominal$DATA";
14 +
    reserve %1 16 8;
15 +
    store w64 %0 %1 0;
16 +
    store w32 4096 %1 8;
17 +
    store w32 4096 %1 12;
18 +
    reserve %2 24 8;
19 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
20 +
    reserve %4 16 8;
21 +
    store w64 %3 %4 0;
22 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
23 +
    load w64 %5 %4 0;
24 +
    load w64 %6 %4 8;
25 +
    load w64 %7 %6 8;
26 +
    zext w32 %8 0;
27 +
    reserve %9 24 8;
28 +
    call w64 %10 %7(%9, %5, 4, 4, 64);
29 +
    load w64 %11 %10 0;
30 +
    reserve %12 16 8;
31 +
    br.ne w32 %11 0 @err2 @ok1;
32 +
  @ok1
33 +
    load w64 %13 %10 8;
34 +
    jmp @fill3(0);
35 +
  @err2
36 +
    unreachable;
37 +
  @fill3(w32 %14)
38 +
    br.ult w32 %14 64 @fill4 @fill5;
39 +
  @fill4
40 +
    mul w64 %15 %14 4;
41 +
    add w64 %16 %13 %15;
42 +
    store w32 %8 %16 0;
43 +
    add w32 %17 %14 1;
44 +
    jmp @fill3(%17);
45 +
  @fill5
46 +
    add w64 %18 %10 8;
47 +
    blit %12 %18 16;
48 +
    jmp @merge6;
49 +
  @merge6
50 +
    load w64 %20 %4 0;
51 +
    load w64 %21 %4 8;
52 +
    load w64 %22 %21 8;
53 +
    reserve %23 1 1;
54 +
    store w8 0 %23 0;
55 +
    reserve %24 24 8;
56 +
    call w64 %25 %22(%24, %20, 1, 1, 64);
57 +
    load w64 %26 %25 0;
58 +
    reserve %27 16 8;
59 +
    br.ne w32 %26 0 @err8 @ok7;
60 +
  @ok7
61 +
    load w64 %28 %25 8;
62 +
    jmp @fill9(0);
63 +
  @err8
64 +
    unreachable;
65 +
  @fill9(w32 %29)
66 +
    br.ult w32 %29 64 @fill10 @fill11;
67 +
  @fill10
68 +
    add w64 %30 %28 %29;
69 +
    blit %30 %23 1;
70 +
    add w32 %31 %29 1;
71 +
    jmp @fill9(%31);
72 +
  @fill11
73 +
    add w64 %32 %25 8;
74 +
    blit %27 %32 16;
75 +
    jmp @merge12;
76 +
  @merge12
77 +
    reserve %33 40 8;
78 +
    blit %33 %12 16;
79 +
    add w64 %35 %33 16;
80 +
    blit %35 %27 16;
81 +
    store w32 0 %33 32;
82 +
    reserve %36 40 8;
83 +
    call w64 %37 $"regions.compiler.regmap::transfer"(%36, %33);
84 +
    load w32 %38 %37 8;
85 +
    br.ult w32 0 %38 @guard#pass13 @guard#trap14;
86 +
  @guard#pass13
87 +
    load w64 %39 %37 0;
88 +
    store w32 40 %39 0;
89 +
    reserve %40 1 1;
90 +
    store w8 2 %40 0;
91 +
    add w64 %41 %37 16;
92 +
    load w32 %42 %41 8;
93 +
    br.ult w32 0 %42 @guard#pass15 @guard#trap16;
94 +
  @guard#trap14
95 +
    ebreak;
96 +
    unreachable;
97 +
  @guard#pass15
98 +
    load w64 %43 %41 0;
99 +
    blit %43 %40 1;
100 +
    store w32 1 %37 32;
101 +
    load w32 %44 %37 8;
102 +
    br.ult w32 0 %44 @guard#pass17 @guard#trap18;
103 +
  @guard#trap16
104 +
    ebreak;
105 +
    unreachable;
106 +
  @guard#pass17
107 +
    load w64 %45 %37 0;
108 +
    load w32 %46 %45 0;
109 +
    add w64 %47 %37 16;
110 +
    load w32 %48 %47 8;
111 +
    br.ult w32 0 %48 @guard#pass19 @guard#trap20;
112 +
  @guard#trap18
113 +
    ebreak;
114 +
    unreachable;
115 +
  @guard#pass19
116 +
    load w64 %49 %47 0;
117 +
    load w8 %50 %49 0;
118 +
    zext w8 %51 %50;
119 +
    add w32 %52 %46 %51;
120 +
    store w32 %52 %45 0;
121 +
    load w32 %53 %37 32;
122 +
    br.eq w32 %53 1 @assert.ok22 @assert.fail21;
123 +
  @guard#trap20
124 +
    ebreak;
125 +
    unreachable;
126 +
  @assert.fail21
127 +
    unreachable;
128 +
  @assert.ok22
129 +
    load w32 %54 %37 8;
130 +
    br.ult w32 63 %54 @guard#pass25 @guard#trap26;
131 +
  @assert.fail23
132 +
    unreachable;
133 +
  @assert.ok24
134 +
    add w64 %59 %37 16;
135 +
    load w32 %60 %59 8;
136 +
    br.ult w32 63 %60 @guard#pass29 @guard#trap30;
137 +
  @guard#pass25
138 +
    load w64 %55 %37 0;
139 +
    mul w64 %56 63 4;
140 +
    add w64 %57 %55 %56;
141 +
    load w32 %58 %57 0;
142 +
    br.eq w32 %58 0 @assert.ok24 @assert.fail23;
143 +
  @guard#trap26
144 +
    ebreak;
145 +
    unreachable;
146 +
  @assert.fail27
147 +
    unreachable;
148 +
  @assert.ok28
149 +
    load w32 %64 %37 8;
150 +
    br.ult w32 0 %64 @guard#pass31 @guard#trap32;
151 +
  @guard#pass29
152 +
    load w64 %61 %59 0;
153 +
    add w64 %62 %61 63;
154 +
    load w8 %63 %62 0;
155 +
    br.eq w8 %63 0 @assert.ok28 @assert.fail27;
156 +
  @guard#trap30
157 +
    ebreak;
158 +
    unreachable;
159 +
  @guard#pass31
160 +
    load w64 %65 %37 0;
161 +
    load w32 %66 %65 0;
162 +
    ret %66;
163 +
  @guard#trap32
164 +
    ebreak;
165 +
    unreachable;
166 +
}
test/tests/regions.compiler.symbol.rad added +36 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
/// One symbol with shared identity and a mutable register index.
7 +
record Symbol: 'graph + Copy {
8 +
    /// Source name in permanent storage.
9 +
    name: *[u8],
10 +
    /// Register index retained by the graph region.
11 +
    index: &'graph cell u32,
12 +
}
13 +
14 +
/// Update a symbol found through a shared table entry.
15 +
fn assign 'graph (symbol: &'graph Symbol 'graph, index: u32) {
16 +
    set *symbol.index = index;
17 +
}
18 +
19 +
@default fn main() -> u32 {
20 +
    static DATA: [u8; 256] = [0; 256];
21 +
    let mut arena = alloc::new(&mut DATA[..]);
22 +
    use arena as graph in {
23 +
        let index = try! graph.new(0 as u32);
24 +
        let description: Symbol 'graph = Symbol { name: "value", index: index as &'graph cell u32 };
25 +
        let owned = try! graph.new(description);
26 +
        let shared: &'graph Symbol 'graph = owned;
27 +
        let byName = try! graph.fill(shared, 2);
28 +
        let byId = try! graph.fill(shared, 2);
29 +
        assert byName[0] == byId[1];
30 +
        assert byName[0].name.len == 5;
31 +
        assign(byName[0], 41);
32 +
        assert *byId[1].index == 41;
33 +
        assign(byId[1], *byName[0].index + 1);
34 +
        return *shared.index;
35 +
    }
36 +
}
test/tests/regions.compiler.symbol.ril added +212 -0
1 +
data mut $"regions.compiler.symbol::regions.compiler.symbol::main$nominal$DATA" align 1 {
2 +
    w8 0 * 256;
3 +
}
4 +
5 +
data $"regions.compiler.symbol::main$literal$0" align 1 {
6 +
    str "value";
7 +
}
8 +
9 +
fn w64 $"regions.compiler.symbol::assign"(w64 %0, w32 %1) {
10 +
  @entry0
11 +
    load w64 %2 %0 16;
12 +
    store w32 %1 %2 0;
13 +
    ret;
14 +
}
15 +
16 +
fn w32 $"regions.compiler.symbol::main"() {
17 +
  @entry0
18 +
    copy %0 $"regions.compiler.symbol::regions.compiler.symbol::main$nominal$DATA";
19 +
    reserve %1 16 8;
20 +
    store w64 %0 %1 0;
21 +
    store w32 256 %1 8;
22 +
    store w32 256 %1 12;
23 +
    reserve %2 24 8;
24 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
25 +
    reserve %4 16 8;
26 +
    store w64 %3 %4 0;
27 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
28 +
    load w64 %5 %4 0;
29 +
    load w64 %6 %4 8;
30 +
    load w64 %7 %6 0;
31 +
    zext w32 %8 0;
32 +
    reserve %9 16 8;
33 +
    call w64 %10 %7(%9, %5, 4, 4);
34 +
    load w64 %11 %10 0;
35 +
    reserve %12 8 8;
36 +
    br.ne w32 %11 0 @err2 @ok1;
37 +
  @ok1
38 +
    load w64 %13 %10 8;
39 +
    store w32 %8 %13 0;
40 +
    load w64 %14 %10 8;
41 +
    store w64 %14 %12 0;
42 +
    jmp @merge3;
43 +
  @err2
44 +
    unreachable;
45 +
  @merge3
46 +
    load w64 %15 %12 0;
47 +
    reserve %16 24 8;
48 +
    copy %17 $"regions.compiler.symbol::main$literal$0";
49 +
    reserve %18 16 8;
50 +
    store w64 %17 %18 0;
51 +
    store w32 5 %18 8;
52 +
    store w32 5 %18 12;
53 +
    blit %16 %18 16;
54 +
    store w64 %15 %16 16;
55 +
    load w64 %19 %4 0;
56 +
    load w64 %20 %4 8;
57 +
    load w64 %21 %20 0;
58 +
    reserve %22 24 8;
59 +
    blit %22 %16 24;
60 +
    reserve %23 16 8;
61 +
    call w64 %24 %21(%23, %19, 24, 8);
62 +
    load w64 %25 %24 0;
63 +
    reserve %26 8 8;
64 +
    br.ne w32 %25 0 @err5 @ok4;
65 +
  @ok4
66 +
    load w64 %27 %24 8;
67 +
    blit %27 %22 24;
68 +
    load w64 %28 %24 8;
69 +
    store w64 %28 %26 0;
70 +
    jmp @merge6;
71 +
  @err5
72 +
    unreachable;
73 +
  @merge6
74 +
    load w64 %29 %26 0;
75 +
    load w64 %30 %4 0;
76 +
    load w64 %31 %4 8;
77 +
    load w64 %32 %31 8;
78 +
    reserve %33 24 8;
79 +
    call w64 %34 %32(%33, %30, 8, 8, 2);
80 +
    load w64 %35 %34 0;
81 +
    reserve %36 16 8;
82 +
    br.ne w32 %35 0 @err8 @ok7;
83 +
  @ok7
84 +
    load w64 %37 %34 8;
85 +
    jmp @fill9(0);
86 +
  @err8
87 +
    unreachable;
88 +
  @fill9(w32 %38)
89 +
    br.ult w32 %38 2 @fill10 @fill11;
90 +
  @fill10
91 +
    mul w64 %39 %38 8;
92 +
    add w64 %40 %37 %39;
93 +
    store w64 %29 %40 0;
94 +
    add w32 %41 %38 1;
95 +
    jmp @fill9(%41);
96 +
  @fill11
97 +
    add w64 %42 %34 8;
98 +
    blit %36 %42 16;
99 +
    jmp @merge12;
100 +
  @merge12
101 +
    load w64 %44 %4 0;
102 +
    load w64 %45 %4 8;
103 +
    load w64 %46 %45 8;
104 +
    reserve %48 24 8;
105 +
    call w64 %49 %46(%48, %44, 8, 8, 2);
106 +
    load w64 %50 %49 0;
107 +
    reserve %51 16 8;
108 +
    br.ne w32 %50 0 @err14 @ok13;
109 +
  @ok13
110 +
    load w64 %52 %49 8;
111 +
    jmp @fill15(0);
112 +
  @err14
113 +
    unreachable;
114 +
  @fill15(w32 %53)
115 +
    br.ult w32 %53 2 @fill16 @fill17;
116 +
  @fill16
117 +
    mul w64 %54 %53 8;
118 +
    add w64 %55 %52 %54;
119 +
    store w64 %29 %55 0;
120 +
    add w32 %56 %53 1;
121 +
    jmp @fill15(%56);
122 +
  @fill17
123 +
    add w64 %57 %49 8;
124 +
    blit %51 %57 16;
125 +
    jmp @merge18;
126 +
  @merge18
127 +
    load w32 %59 %36 8;
128 +
    br.ult w32 0 %59 @guard#pass21 @guard#trap22;
129 +
  @assert.fail19
130 +
    unreachable;
131 +
  @assert.ok20
132 +
    load w32 %67 %36 8;
133 +
    br.ult w32 0 %67 @guard#pass27 @guard#trap28;
134 +
  @guard#pass21
135 +
    load w64 %60 %36 0;
136 +
    load w64 %61 %60 0;
137 +
    load w32 %62 %51 8;
138 +
    br.ult w32 1 %62 @guard#pass23 @guard#trap24;
139 +
  @guard#trap22
140 +
    ebreak;
141 +
    unreachable;
142 +
  @guard#pass23
143 +
    load w64 %63 %51 0;
144 +
    mul w64 %64 1 8;
145 +
    add w64 %65 %63 %64;
146 +
    load w64 %66 %65 0;
147 +
    br.eq w64 %61 %66 @assert.ok20 @assert.fail19;
148 +
  @guard#trap24
149 +
    ebreak;
150 +
    unreachable;
151 +
  @assert.fail25
152 +
    unreachable;
153 +
  @assert.ok26
154 +
    load w32 %71 %36 8;
155 +
    br.ult w32 0 %71 @guard#pass29 @guard#trap30;
156 +
  @guard#pass27
157 +
    load w64 %68 %36 0;
158 +
    load w64 %69 %68 0;
159 +
    load w32 %70 %69 8;
160 +
    br.eq w32 %70 5 @assert.ok26 @assert.fail25;
161 +
  @guard#trap28
162 +
    ebreak;
163 +
    unreachable;
164 +
  @guard#pass29
165 +
    load w64 %72 %36 0;
166 +
    load w64 %73 %72 0;
167 +
    call w64 $"regions.compiler.symbol::assign"(%73, 41);
168 +
    load w32 %74 %51 8;
169 +
    br.ult w32 1 %74 @guard#pass33 @guard#trap34;
170 +
  @guard#trap30
171 +
    ebreak;
172 +
    unreachable;
173 +
  @assert.fail31
174 +
    unreachable;
175 +
  @assert.ok32
176 +
    load w32 %81 %51 8;
177 +
    br.ult w32 1 %81 @guard#pass35 @guard#trap36;
178 +
  @guard#pass33
179 +
    load w64 %75 %51 0;
180 +
    mul w64 %76 1 8;
181 +
    add w64 %77 %75 %76;
182 +
    load w64 %78 %77 0;
183 +
    load w64 %79 %78 16;
184 +
    load w32 %80 %79 0;
185 +
    br.eq w32 %80 41 @assert.ok32 @assert.fail31;
186 +
  @guard#trap34
187 +
    ebreak;
188 +
    unreachable;
189 +
  @guard#pass35
190 +
    load w64 %82 %51 0;
191 +
    mul w64 %83 1 8;
192 +
    add w64 %84 %82 %83;
193 +
    load w64 %85 %84 0;
194 +
    load w32 %86 %36 8;
195 +
    br.ult w32 0 %86 @guard#pass37 @guard#trap38;
196 +
  @guard#trap36
197 +
    ebreak;
198 +
    unreachable;
199 +
  @guard#pass37
200 +
    load w64 %87 %36 0;
201 +
    load w64 %88 %87 0;
202 +
    load w64 %89 %88 16;
203 +
    load w32 %90 %89 0;
204 +
    add w32 %91 %90 1;
205 +
    call w64 $"regions.compiler.symbol::assign"(%85, %91);
206 +
    load w64 %93 %29 16;
207 +
    load w32 %94 %93 0;
208 +
    ret %94;
209 +
  @guard#trap38
210 +
    ebreak;
211 +
    unreachable;
212 +
}
test/tests/regions.compiler.writer.rad added +46 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
/// Instruction buffer with one exclusive writer.
7 +
record Writer: 'output {
8 +
    /// Instruction storage retained by the output region.
9 +
    code: &'output mut [u32],
10 +
    /// Number of initialized output words.
11 +
    len: u32,
12 +
}
13 +
14 +
/// Append one instruction within the fixed output capacity.
15 +
fn emit 'output (writer: &mut Writer 'output, instruction: u32) {
16 +
    assert writer.len < writer.code.len, "emit: code buffer full";
17 +
    set writer.code[writer.len] = instruction;
18 +
    set writer.len += 1;
19 +
}
20 +
21 +
/// Patch an instruction already present in the output.
22 +
fn patch 'output (writer: &mut Writer 'output, offset: u32, instruction: u32) {
23 +
    assert offset < writer.len;
24 +
    set writer.code[offset] = instruction;
25 +
}
26 +
27 +
/// Publish initialized output and consume the writer's exclusive access.
28 +
fn finish 'output (writer: Writer 'output) -> &'output [u32] {
29 +
    return &writer.code[..writer.len];
30 +
}
31 +
32 +
@default fn main() -> u32 {
33 +
    static DATA: [u8; 128] = [0; 128];
34 +
    let mut arena = alloc::new(&mut DATA[..]);
35 +
    use arena as output in {
36 +
        let code = try! output.fill(0 as u32, 16);
37 +
        let mut writer: Writer 'output = Writer { code, len: 0 };
38 +
        emit(&mut writer, 11);
39 +
        emit(&mut writer, 20);
40 +
        emit(&mut writer, 12);
41 +
        patch(&mut writer, 1, 19);
42 +
        let finished = finish(writer);
43 +
        assert finished.len == 3;
44 +
        return finished[0] + finished[1] + finished[2];
45 +
    }
46 +
}
test/tests/regions.compiler.writer.ril added +152 -0
1 +
data mut $"regions.compiler.writer::regions.compiler.writer::main$nominal$DATA" align 1 {
2 +
    w8 0 * 128;
3 +
}
4 +
5 +
fn w64 $"regions.compiler.writer::emit"(w64 %0, w32 %1) {
6 +
  @entry0
7 +
    load w32 %2 %0 16;
8 +
    load w32 %3 %0 8;
9 +
    br.ult w32 %2 %3 @assert.ok2 @assert.fail1;
10 +
  @assert.fail1
11 +
    unreachable;
12 +
  @assert.ok2
13 +
    load w32 %4 %0 16;
14 +
    load w32 %5 %0 8;
15 +
    br.ult w32 %4 %5 @guard#pass3 @guard#trap4;
16 +
  @guard#pass3
17 +
    load w64 %6 %0 0;
18 +
    mul w64 %7 %4 4;
19 +
    add w64 %8 %6 %7;
20 +
    store w32 %1 %8 0;
21 +
    load w32 %9 %0 16;
22 +
    add w32 %10 %9 1;
23 +
    store w32 %10 %0 16;
24 +
    ret;
25 +
  @guard#trap4
26 +
    ebreak;
27 +
    unreachable;
28 +
}
29 +
30 +
fn w64 $"regions.compiler.writer::patch"(w64 %0, w32 %1, w32 %2) {
31 +
  @entry0
32 +
    load w32 %3 %0 16;
33 +
    br.ult w32 %1 %3 @assert.ok2 @assert.fail1;
34 +
  @assert.fail1
35 +
    unreachable;
36 +
  @assert.ok2
37 +
    load w32 %4 %0 8;
38 +
    br.ult w32 %1 %4 @guard#pass3 @guard#trap4;
39 +
  @guard#pass3
40 +
    load w64 %5 %0 0;
41 +
    mul w64 %6 %1 4;
42 +
    add w64 %7 %5 %6;
43 +
    store w32 %2 %7 0;
44 +
    ret;
45 +
  @guard#trap4
46 +
    ebreak;
47 +
    unreachable;
48 +
}
49 +
50 +
fn w64 $"regions.compiler.writer::finish"(w64 %0, w64 %1) {
51 +
  @entry0
52 +
    load w64 %2 %1 0;
53 +
    load w32 %3 %1 8;
54 +
    load w32 %4 %1 16;
55 +
    br.ult w32 %3 %4 @guard#trap1 @guard#pass2;
56 +
  @guard#trap1
57 +
    ebreak;
58 +
    unreachable;
59 +
  @guard#pass2
60 +
    reserve %5 16 8;
61 +
    store w64 %2 %5 0;
62 +
    store w32 %4 %5 8;
63 +
    store w32 %4 %5 12;
64 +
    blit %0 %5 16;
65 +
    ret %0;
66 +
}
67 +
68 +
fn w32 $"regions.compiler.writer::main"() {
69 +
  @entry0
70 +
    copy %0 $"regions.compiler.writer::regions.compiler.writer::main$nominal$DATA";
71 +
    reserve %1 16 8;
72 +
    store w64 %0 %1 0;
73 +
    store w32 128 %1 8;
74 +
    store w32 128 %1 12;
75 +
    reserve %2 24 8;
76 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
77 +
    reserve %4 16 8;
78 +
    store w64 %3 %4 0;
79 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
80 +
    load w64 %5 %4 0;
81 +
    load w64 %6 %4 8;
82 +
    load w64 %7 %6 8;
83 +
    zext w32 %8 0;
84 +
    reserve %9 24 8;
85 +
    call w64 %10 %7(%9, %5, 4, 4, 16);
86 +
    load w64 %11 %10 0;
87 +
    reserve %12 16 8;
88 +
    br.ne w32 %11 0 @err2 @ok1;
89 +
  @ok1
90 +
    load w64 %13 %10 8;
91 +
    jmp @fill3(0);
92 +
  @err2
93 +
    unreachable;
94 +
  @fill3(w32 %14)
95 +
    br.ult w32 %14 16 @fill4 @fill5;
96 +
  @fill4
97 +
    mul w64 %15 %14 4;
98 +
    add w64 %16 %13 %15;
99 +
    store w32 %8 %16 0;
100 +
    add w32 %17 %14 1;
101 +
    jmp @fill3(%17);
102 +
  @fill5
103 +
    add w64 %18 %10 8;
104 +
    blit %12 %18 16;
105 +
    jmp @merge6;
106 +
  @merge6
107 +
    reserve %19 24 8;
108 +
    blit %19 %12 16;
109 +
    store w32 0 %19 16;
110 +
    call w64 $"regions.compiler.writer::emit"(%19, 11);
111 +
    call w64 $"regions.compiler.writer::emit"(%19, 20);
112 +
    call w64 $"regions.compiler.writer::emit"(%19, 12);
113 +
    call w64 $"regions.compiler.writer::patch"(%19, 1, 19);
114 +
    reserve %20 16 8;
115 +
    call w64 %21 $"regions.compiler.writer::finish"(%20, %19);
116 +
    load w32 %22 %21 8;
117 +
    br.eq w32 %22 3 @assert.ok8 @assert.fail7;
118 +
  @assert.fail7
119 +
    unreachable;
120 +
  @assert.ok8
121 +
    load w32 %23 %21 8;
122 +
    br.ult w32 0 %23 @guard#pass9 @guard#trap10;
123 +
  @guard#pass9
124 +
    load w64 %24 %21 0;
125 +
    load w32 %25 %24 0;
126 +
    load w32 %26 %21 8;
127 +
    br.ult w32 1 %26 @guard#pass11 @guard#trap12;
128 +
  @guard#trap10
129 +
    ebreak;
130 +
    unreachable;
131 +
  @guard#pass11
132 +
    load w64 %27 %21 0;
133 +
    mul w64 %28 1 4;
134 +
    add w64 %29 %27 %28;
135 +
    load w32 %30 %29 0;
136 +
    add w32 %31 %25 %30;
137 +
    load w32 %32 %21 8;
138 +
    br.ult w32 2 %32 @guard#pass13 @guard#trap14;
139 +
  @guard#trap12
140 +
    ebreak;
141 +
    unreachable;
142 +
  @guard#pass13
143 +
    load w64 %33 %21 0;
144 +
    mul w64 %34 2 4;
145 +
    add w64 %35 %33 %34;
146 +
    load w32 %36 %35 0;
147 +
    add w32 %37 %31 %36;
148 +
    ret %37;
149 +
  @guard#trap14
150 +
    ebreak;
151 +
    unreachable;
152 +
}
test/tests/regions.constant.optional.rad added +16 -0
1 +
//! returns: 42
2 +
3 +
/// Value with a regional name alternative.
4 +
union Value: 'r + Copy { Imm(i64), Name(&'r [u8]) }
5 +
/// Instruction with an optional regional payload.
6 +
union Instruction: 'r + Copy { Ret { value: ?Value 'r } }
7 +
@default fn main() -> u32 {
8 +
    let name = "test";
9 +
    let input: 'r = &name[..] in {
10 +
        let instructions = &[Instruction 'r::Ret { value: Value 'r::Imm(42) }];
11 +
        let case Instruction 'r::Ret { value } = instructions[0] else panic;
12 +
        let present = value else panic;
13 +
        let case Value 'r::Imm(number) = present else panic;
14 +
        return number as u32;
15 +
    }
16 +
}
test/tests/regions.constant.optional.ril added +73 -0
1 +
data $main$literal$0 align 1 {
2 +
    str "test";
3 +
}
4 +
5 +
data $main$literal$1 align 8 {
6 +
    w8 0;
7 +
    undef * 7;
8 +
    w8 1;
9 +
    undef * 7;
10 +
    w8 0;
11 +
    undef * 7;
12 +
    w64 42;
13 +
    undef * 8;
14 +
}
15 +
16 +
fn w32 $main() {
17 +
  @entry0
18 +
    copy %0 $main$literal$0;
19 +
    reserve %1 16 8;
20 +
    store w64 %0 %1 0;
21 +
    store w32 4 %1 8;
22 +
    store w32 4 %1 12;
23 +
    load w64 %2 %1 0;
24 +
    load w32 %3 %1 8;
25 +
    reserve %4 16 8;
26 +
    store w64 %2 %4 0;
27 +
    store w32 %3 %4 8;
28 +
    store w32 %3 %4 12;
29 +
    copy %5 $main$literal$1;
30 +
    reserve %6 16 8;
31 +
    store w64 %5 %6 0;
32 +
    store w32 1 %6 8;
33 +
    store w32 1 %6 12;
34 +
    load w32 %7 %6 8;
35 +
    br.ult w32 0 %7 @guard#pass1 @guard#trap2;
36 +
  @guard#pass1
37 +
    load w64 %8 %6 0;
38 +
    reserve %9 40 8;
39 +
    blit %9 %8 40;
40 +
    load w8 %10 %9 0;
41 +
    br.eq w8 %10 0 @success3 @else4;
42 +
  @guard#trap2
43 +
    ebreak;
44 +
    unreachable;
45 +
  @success3
46 +
    add w64 %11 %9 8;
47 +
    jmp @merge5;
48 +
  @else4
49 +
    unreachable;
50 +
  @merge5
51 +
    reserve %12 32 8;
52 +
    blit %12 %11 32;
53 +
    load w8 %13 %12 0;
54 +
    br.ne w32 %13 0 @success6 @else7;
55 +
  @success6
56 +
    add w64 %14 %12 8;
57 +
    jmp @merge8;
58 +
  @else7
59 +
    unreachable;
60 +
  @merge8
61 +
    reserve %15 24 8;
62 +
    blit %15 %14 24;
63 +
    load w8 %16 %15 0;
64 +
    br.eq w8 %16 0 @success9 @else10;
65 +
  @success9
66 +
    sload w64 %17 %15 8;
67 +
    jmp @merge11;
68 +
  @else10
69 +
    unreachable;
70 +
  @merge11
71 +
    zext w32 %18 %17;
72 +
    ret %18;
73 +
}
test/tests/regions.copy.binding.rad added +64 -0
1 +
//! returns: 42
2 +
3 +
/// A shared reference that can be replaced without moving its target.
4 +
record Holder: 'r {
5 +
    /// Current target within the declared region.
6 +
    current: &'r u32,
7 +
}
8 +
9 +
/// Replace a stored reference and read the previous target.
10 +
fn replace 'r (self: &mut Holder 'r, next: &'r u32) -> u32 {
11 +
    let previous = self.current;
12 +
    set self.current = next;
13 +
    return *previous;
14 +
}
15 +
16 +
/// Rebind a copied reference within its declared region.
17 +
fn follow 'r (first: &'r u32, second: &'r u32) -> u32 {
18 +
    let mut cursor = first;
19 +
    set cursor = second;
20 +
    return *cursor;
21 +
}
22 +
23 +
/// Rebind a shared slice and read its new target.
24 +
fn followSlice 'r (first: &'r [u32], second: &'r [u32]) -> u32 {
25 +
    let mut cursor = first;
26 +
    assert cursor[0] == 20;
27 +
    set cursor = second;
28 +
    return cursor[0];
29 +
}
30 +
31 +
/// Write through two successive cell references.
32 +
fn followCell 'r (first: &'r cell u32, second: &'r cell u32) {
33 +
    let mut cursor = first;
34 +
    set *cursor = 20;
35 +
    set cursor = second;
36 +
    set *cursor = 22;
37 +
}
38 +
39 +
@default fn main() -> u32 {
40 +
    let first: u32 = 20;
41 +
    let second: u32 = 22;
42 +
    let mut result: u32 = 0;
43 +
    let a: 'values = &first, b = &second in {
44 +
        let mut holder = Holder 'values { current: a };
45 +
        set result = replace(&mut holder, b) + follow(a, holder.current);
46 +
    }
47 +
    let xs: [u32; 1] = [20];
48 +
    let ys: [u32; 1] = [22];
49 +
    let a: 'slices = &xs[..], b = &ys[..] in {
50 +
        assert followSlice(a, b) == 22;
51 +
    }
52 +
    let mut x: u32 = 0;
53 +
    let mut y: u32 = 0;
54 +
    let a: 'cells = &mut x, b = &mut y in {
55 +
        let firstCell = a as &'cells cell u32;
56 +
        let secondCell = b as &'cells cell u32;
57 +
        followCell(firstCell, secondCell);
58 +
        assert *firstCell == 20;
59 +
        assert *secondCell == 22;
60 +
    }
61 +
    assert x == 20;
62 +
    assert y == 22;
63 +
    return result;
64 +
}
test/tests/regions.copy.binding.ril added +107 -0
1 +
fn w32 $replace(w64 %0, w64 %1) {
2 +
  @entry0
3 +
    load w64 %2 %0 0;
4 +
    store w64 %1 %0 0;
5 +
    load w32 %3 %2 0;
6 +
    ret %3;
7 +
}
8 +
9 +
fn w32 $follow(w64 %0, w64 %1) {
10 +
  @entry0
11 +
    load w32 %2 %1 0;
12 +
    ret %2;
13 +
}
14 +
15 +
fn w32 $followSlice(w64 %0, w64 %1) {
16 +
  @entry0
17 +
    reserve %2 16 8;
18 +
    blit %2 %0 16;
19 +
    load w32 %3 %2 8;
20 +
    br.ult w32 0 %3 @guard#pass3 @guard#trap4;
21 +
  @assert.fail1
22 +
    unreachable;
23 +
  @assert.ok2
24 +
    blit %2 %1 16;
25 +
    load w32 %6 %2 8;
26 +
    br.ult w32 0 %6 @guard#pass5 @guard#trap6;
27 +
  @guard#pass3
28 +
    load w64 %4 %2 0;
29 +
    load w32 %5 %4 0;
30 +
    br.eq w32 %5 20 @assert.ok2 @assert.fail1;
31 +
  @guard#trap4
32 +
    ebreak;
33 +
    unreachable;
34 +
  @guard#pass5
35 +
    load w64 %7 %2 0;
36 +
    load w32 %8 %7 0;
37 +
    ret %8;
38 +
  @guard#trap6
39 +
    ebreak;
40 +
    unreachable;
41 +
}
42 +
43 +
fn w64 $followCell(w64 %0, w64 %1) {
44 +
  @entry0
45 +
    store w32 20 %0 0;
46 +
    store w32 22 %1 0;
47 +
    ret;
48 +
}
49 +
50 +
fn w32 $main() {
51 +
  @entry0
52 +
    reserve %0 4 4;
53 +
    store w32 20 %0 0;
54 +
    reserve %1 4 4;
55 +
    store w32 22 %1 0;
56 +
    reserve %2 8 8;
57 +
    store w64 %0 %2 0;
58 +
    call w32 %3 $replace(%2, %1);
59 +
    load w64 %4 %2 0;
60 +
    call w32 %5 $follow(%0, %4);
61 +
    add w32 %6 %3 %5;
62 +
    reserve %7 4 4;
63 +
    store w32 20 %7 0;
64 +
    reserve %8 4 4;
65 +
    store w32 22 %8 0;
66 +
    reserve %9 16 8;
67 +
    store w64 %7 %9 0;
68 +
    store w32 1 %9 8;
69 +
    store w32 1 %9 12;
70 +
    reserve %10 16 8;
71 +
    store w64 %8 %10 0;
72 +
    store w32 1 %10 8;
73 +
    store w32 1 %10 12;
74 +
    reserve %11 16 8;
75 +
    blit %11 %9 16;
76 +
    call w32 %12 $followSlice(%11, %10);
77 +
    br.eq w32 %12 22 @assert.ok2 @assert.fail1;
78 +
  @assert.fail1
79 +
    unreachable;
80 +
  @assert.ok2
81 +
    reserve %13 4 4;
82 +
    store w32 0 %13 0;
83 +
    reserve %14 4 4;
84 +
    store w32 0 %14 0;
85 +
    call w64 $followCell(%13, %14);
86 +
    load w32 %15 %13 0;
87 +
    br.eq w32 %15 20 @assert.ok4 @assert.fail3;
88 +
  @assert.fail3
89 +
    unreachable;
90 +
  @assert.ok4
91 +
    load w32 %16 %14 0;
92 +
    br.eq w32 %16 22 @assert.ok6 @assert.fail5;
93 +
  @assert.fail5
94 +
    unreachable;
95 +
  @assert.ok6
96 +
    load w32 %17 %13 0;
97 +
    br.eq w32 %17 20 @assert.ok8 @assert.fail7;
98 +
  @assert.fail7
99 +
    unreachable;
100 +
  @assert.ok8
101 +
    load w32 %18 %14 0;
102 +
    br.eq w32 %18 22 @assert.ok10 @assert.fail9;
103 +
  @assert.fail9
104 +
    unreachable;
105 +
  @assert.ok10
106 +
    ret %6;
107 +
}
test/tests/regions.loans.control.rad added +76 -0
1 +
//! returns: 42
2 +
3 +
record Pair { left: u32, right: u32 }
4 +
5 +
fn split 'r (p: &'r mut Pair) -> u32 {
6 +
    let a = &mut p.left;
7 +
    let b = &mut p.right;
8 +
    set *a += 1;
9 +
    set *b += 1;
10 +
    return *a + *b;
11 +
}
12 +
13 +
fn branch 'r (p: &'r mut Pair, condition: bool) -> u32 {
14 +
    if condition {
15 +
        let q = &mut p.left;
16 +
        set *q = 7;
17 +
    } else {
18 +
        set p.left = 8;
19 +
    }
20 +
    return p.right;
21 +
}
22 +
23 +
fn returnedBranch 'r (p: &'r mut u32, condition: bool) -> u32 {
24 +
    if condition {
25 +
        let q = &mut *p;
26 +
        return *q;
27 +
    }
28 +
    return *p;
29 +
}
30 +
31 +
fn readLoop 'r (p: &'r u32) -> u32 {
32 +
    let mut sum: u32 = 0;
33 +
    for i in 0..3 {
34 +
        let q = &*p;
35 +
        set sum += *q;
36 +
    }
37 +
    let mut count: u32 = 0;
38 +
    while count < 2 {
39 +
        let q = &*p;
40 +
        assert *q > 0;
41 +
        set count += 1;
42 +
    }
43 +
    let mut next: ?u32 = 1;
44 +
    while let n = next {
45 +
        let q = &*p;
46 +
        assert *q > 0;
47 +
        set next = nil;
48 +
    }
49 +
    return sum;
50 +
}
51 +
52 +
fn breakChild 'r (p: &'r mut u32) {
53 +
    loop {
54 +
        let q: 'iteration = &mut *p where 'r: 'iteration in {
55 +
            let value = &mut *q;
56 +
            set *value += 1;
57 +
            break;
58 +
        }
59 +
    }
60 +
    set *p += 1;
61 +
}
62 +
63 +
@default fn main() -> u32 {
64 +
    let mut pair = Pair { left: 20, right: 20 };
65 +
    let p: 'split = &mut pair in { assert split(p) == 42; }
66 +
    let mut other = Pair { left: 0, right: 9 };
67 +
    let p: 'first = &mut other in { assert branch(p, true) == 9; }
68 +
    let p: 'second = &mut other in { assert branch(p, false) == 9; }
69 +
    let p: 'shared = &pair.left in { assert readLoop(p) == 63; }
70 +
    let mut value: u32 = 0;
71 +
    let p: 'break = &mut value in { breakChild(p); }
72 +
    assert value == 2;
73 +
    let p: 'returned = &mut value in { assert returnedBranch(p, true) == 2; }
74 +
    let p: 'continued = &mut value in { assert returnedBranch(p, false) == 2; }
75 +
    return pair.left + pair.right;
76 +
}
test/tests/regions.loans.control.ril added +153 -0
1 +
fn w32 $split(w64 %0) {
2 +
  @entry0
3 +
    add w64 %1 %0 4;
4 +
    load w32 %2 %0 0;
5 +
    add w32 %3 %2 1;
6 +
    store w32 %3 %0 0;
7 +
    load w32 %4 %1 0;
8 +
    add w32 %5 %4 1;
9 +
    store w32 %5 %1 0;
10 +
    load w32 %6 %0 0;
11 +
    load w32 %7 %1 0;
12 +
    add w32 %8 %6 %7;
13 +
    ret %8;
14 +
}
15 +
16 +
fn w32 $branch(w64 %0, w8 %1) {
17 +
  @entry0
18 +
    br.ne w32 %1 0 @then1 @else2;
19 +
  @then1
20 +
    store w32 7 %0 0;
21 +
    jmp @merge3;
22 +
  @else2
23 +
    store w32 8 %0 0;
24 +
    jmp @merge3;
25 +
  @merge3
26 +
    load w32 %3 %0 4;
27 +
    ret %3;
28 +
}
29 +
30 +
fn w32 $returnedBranch(w64 %0, w8 %1) {
31 +
  @entry0
32 +
    br.ne w32 %1 0 @then1 @merge2;
33 +
  @then1
34 +
    load w32 %2 %0 0;
35 +
    ret %2;
36 +
  @merge2
37 +
    load w32 %3 %0 0;
38 +
    ret %3;
39 +
}
40 +
41 +
fn w32 $readLoop(w64 %0) {
42 +
  @entry0
43 +
    jmp @loop1(0, %0, 0);
44 +
  @loop1(w64 %1, w64 %2, w32 %3)
45 +
    br.slt w64 %1 3 @body2 @merge3;
46 +
  @body2
47 +
    load w32 %4 %2 0;
48 +
    add w32 %5 %3 %4;
49 +
    add w64 %6 %1 1;
50 +
    jmp @loop1(%6, %2, %5);
51 +
  @merge3
52 +
    jmp @while4(0, %2);
53 +
  @while4(w32 %7, w64 %8)
54 +
    br.ult w32 %7 2 @body5 @merge6;
55 +
  @body5
56 +
    load w32 %9 %8 0;
57 +
    br.ult w32 0 %9 @assert.ok8 @assert.fail7;
58 +
  @merge6
59 +
    reserve %11 8 4;
60 +
    store w8 1 %11 0;
61 +
    store w32 1 %11 4;
62 +
    jmp @while9(%11, %8);
63 +
  @assert.fail7
64 +
    unreachable;
65 +
  @assert.ok8
66 +
    add w32 %10 %7 1;
67 +
    jmp @while4(%10, %8);
68 +
  @while9(w64 %12, w64 %16)
69 +
    reserve %13 8 4;
70 +
    blit %13 %12 8;
71 +
    load w8 %14 %13 0;
72 +
    br.ne w32 %14 0 @body10 @merge11;
73 +
  @body10
74 +
    load w32 %15 %13 4;
75 +
    load w32 %17 %16 0;
76 +
    br.ult w32 0 %17 @assert.ok13 @assert.fail12;
77 +
  @merge11
78 +
    ret %3;
79 +
  @assert.fail12
80 +
    unreachable;
81 +
  @assert.ok13
82 +
    reserve %18 8 4;
83 +
    store w8 0 %18 0;
84 +
    blit %12 %18 8;
85 +
    jmp @while9(%12, %16);
86 +
}
87 +
88 +
fn w64 $breakChild(w64 %0) {
89 +
  @entry0
90 +
    jmp @loop1(%0);
91 +
  @loop1(w64 %1)
92 +
    load w32 %2 %1 0;
93 +
    add w32 %3 %2 1;
94 +
    store w32 %3 %1 0;
95 +
    jmp @merge2;
96 +
  @merge2
97 +
    load w32 %4 %1 0;
98 +
    add w32 %5 %4 1;
99 +
    store w32 %5 %1 0;
100 +
    ret;
101 +
}
102 +
103 +
fn w32 $main() {
104 +
  @entry0
105 +
    reserve %0 8 4;
106 +
    store w32 20 %0 0;
107 +
    store w32 20 %0 4;
108 +
    call w32 %1 $split(%0);
109 +
    br.eq w32 %1 42 @assert.ok2 @assert.fail1;
110 +
  @assert.fail1
111 +
    unreachable;
112 +
  @assert.ok2
113 +
    reserve %2 8 4;
114 +
    store w32 0 %2 0;
115 +
    store w32 9 %2 4;
116 +
    call w32 %3 $branch(%2, 1);
117 +
    br.eq w32 %3 9 @assert.ok4 @assert.fail3;
118 +
  @assert.fail3
119 +
    unreachable;
120 +
  @assert.ok4
121 +
    call w32 %4 $branch(%2, 0);
122 +
    br.eq w32 %4 9 @assert.ok6 @assert.fail5;
123 +
  @assert.fail5
124 +
    unreachable;
125 +
  @assert.ok6
126 +
    call w32 %5 $readLoop(%0);
127 +
    br.eq w32 %5 63 @assert.ok8 @assert.fail7;
128 +
  @assert.fail7
129 +
    unreachable;
130 +
  @assert.ok8
131 +
    reserve %6 4 4;
132 +
    store w32 0 %6 0;
133 +
    call w64 $breakChild(%6);
134 +
    load w32 %7 %6 0;
135 +
    br.eq w32 %7 2 @assert.ok10 @assert.fail9;
136 +
  @assert.fail9
137 +
    unreachable;
138 +
  @assert.ok10
139 +
    call w32 %8 $returnedBranch(%6, 1);
140 +
    br.eq w32 %8 2 @assert.ok12 @assert.fail11;
141 +
  @assert.fail11
142 +
    unreachable;
143 +
  @assert.ok12
144 +
    call w32 %9 $returnedBranch(%6, 0);
145 +
    br.eq w32 %9 2 @assert.ok14 @assert.fail13;
146 +
  @assert.fail13
147 +
    unreachable;
148 +
  @assert.ok14
149 +
    load w32 %10 %0 0;
150 +
    load w32 %11 %0 4;
151 +
    add w32 %12 %10 %11;
152 +
    ret %12;
153 +
}
test/tests/regions.methods.rad added +56 -0
1 +
//! returns: 42
2 +
3 +
/// Value tied to one lexical region.
4 +
record View: 'r + Copy {
5 +
    /// Borrowed value.
6 +
    value: &'r u32,
7 +
}
8 +
9 +
/// Return the value retained by a regional receiver.
10 +
fn (view: &View 'r) get 'r () -> &'r u32 {
11 +
    return view.value;
12 +
}
13 +
14 +
/// Select a value with a call-specific region.
15 +
trait Pick {
16 +
    /// Return the selected value.
17 +
    fn (&Pick) pick 'r (value: &'r u32) -> &'r u32;
18 +
}
19 +
20 +
/// Stateless selector.
21 +
record Picker: Copy {}
22 +
23 +
instance Pick for Picker {
24 +
    /// Return the selected value.
25 +
    fn (picker: &Picker) pick 'r (value: &'r u32) -> &'r u32 {
26 +
        return value;
27 +
    }
28 +
}
29 +
30 +
/// Read a stored value.
31 +
trait Read {
32 +
    /// Return the stored value.
33 +
    fn (&Read) read() -> u32;
34 +
}
35 +
36 +
instance Read for View 'r {
37 +
    /// Return the regional value.
38 +
    fn (view: &View 'r) read() -> u32 {
39 +
        return *view.value;
40 +
    }
41 +
}
42 +
43 +
@default unsafe fn main() -> u32 {
44 +
    let value: u32 = 42;
45 +
    let borrowed: 'value = &value in {
46 +
        let view = View 'value { value: borrowed };
47 +
        assert *view.get() == 42;
48 +
49 +
        let picker = Picker {};
50 +
        let pick: *unsafe opaque Pick = &picker;
51 +
        assert *pick.pick(borrowed) == 42;
52 +
53 +
        let read: *unsafe opaque Read = &view;
54 +
        return read.read();
55 +
    }
56 +
}
test/tests/regions.nominal.rad added +47 -0
1 +
//! returns: 42
2 +
3 +
record Count: 'r + Copy { value: u32 }
4 +
record Pair: 'r + Copy (u32, u32);
5 +
record Node: 'r + Copy { value: u32, next: ?*Node 'r }
6 +
union Item: 'r + Copy { Value(u32), Link { node: ?*Node 'r }, Empty }
7 +
8 +
fn create 'r (value: u32) -> Count 'r { return Count { value }; }
9 +
fn empty 'r () -> Item 'r { return Item::Empty; }
10 +
fn read 'r (count: Count 'r) -> u32 { return count.value; }
11 +
fn sum 'r (pair: Pair 'r) -> u32 {
12 +
    let case Pair(a, b) = pair else panic;
13 +
    return a + b;
14 +
}
15 +
fn itemValue 'r (item: Item 'r) -> u32 {
16 +
    match item {
17 +
        case Item::Value(value) => return value,
18 +
        case Item::Link { node } => {
19 +
            if let n = node {
20 +
                return n.value;
21 +
            }
22 +
            return 0;
23 +
        }
24 +
        case Item::Empty => return 0,
25 +
    }
26 +
}
27 +
fn load 'r 'b (node: &'b Node 'r) -> u32 { return node.value; }
28 +
29 +
@default fn main() -> u32 {
30 +
    let x: u32 = 0;
31 +
    let p: 'first = &x in {
32 +
        let count = create 'first (20);
33 +
        let pair: Pair 'first = Pair(1, 1);
34 +
        let node = Node 'first { value: 20, next: nil };
35 +
        let item: Item 'first = Item::Value(read(count));
36 +
        let none = empty 'first ();
37 +
        let link = Item 'first::Link { node: nil };
38 +
        assert itemValue(none) == 0;
39 +
        assert itemValue(link) == 0;
40 +
        let n: 'second = &node in {
41 +
            assert load(n) == 20;
42 +
            let other = Count 'second { value: 22 };
43 +
            assert read(other) == 22;
44 +
        }
45 +
        return itemValue(item) + sum(pair) + node.value;
46 +
    }
47 +
}
test/tests/regions.nominal.ril added +132 -0
1 +
fn w64 $create(w32 %0) {
2 +
  @entry0
3 +
    reserve %1 4 4;
4 +
    store w32 %0 %1 0;
5 +
    reserve %2 8 8;
6 +
    store w64 0 %2 0;
7 +
    blit %2 %1 4;
8 +
    load w64 %3 %2 0;
9 +
    ret %3;
10 +
}
11 +
12 +
fn w64 $empty(w64 %0) {
13 +
  @entry0
14 +
    reserve %1 16 8;
15 +
    store w8 2 %1 0;
16 +
    blit %0 %1 16;
17 +
    ret %0;
18 +
}
19 +
20 +
fn w32 $read(w64 %0) {
21 +
  @entry0
22 +
    load w32 %1 %0 0;
23 +
    ret %1;
24 +
}
25 +
26 +
fn w32 $sum(w64 %0) {
27 +
  @entry0
28 +
    reserve %1 8 4;
29 +
    blit %1 %0 8;
30 +
    jmp @success1;
31 +
  @success1
32 +
    load w32 %2 %1 0;
33 +
    load w32 %3 %1 4;
34 +
    jmp @merge3;
35 +
  @else2
36 +
    unreachable;
37 +
  @merge3
38 +
    add w32 %4 %2 %3;
39 +
    ret %4;
40 +
}
41 +
42 +
fn w32 $itemValue(w64 %0) {
43 +
  @entry0
44 +
    reserve %1 16 8;
45 +
    blit %1 %0 16;
46 +
    jmp @arm1;
47 +
  @arm1
48 +
    load w8 %2 %1 0;
49 +
    br.eq w8 %2 0 @case2 @arm3;
50 +
  @case2
51 +
    load w32 %3 %1 8;
52 +
    ret %3;
53 +
  @arm3
54 +
    load w8 %4 %1 0;
55 +
    br.eq w8 %4 1 @case4 @arm5;
56 +
  @case4
57 +
    add w64 %5 %1 8;
58 +
    load w64 %6 %5 0;
59 +
    br.ne w32 %6 0 @then6 @else7;
60 +
  @arm5
61 +
    jmp @case9;
62 +
  @then6
63 +
    load w32 %7 %6 0;
64 +
    ret %7;
65 +
  @else7
66 +
    jmp @merge8;
67 +
  @merge8
68 +
    ret 0;
69 +
  @case9
70 +
    ret 0;
71 +
}
72 +
73 +
fn w32 $load(w64 %0) {
74 +
  @entry0
75 +
    load w32 %1 %0 0;
76 +
    ret %1;
77 +
}
78 +
79 +
fn w32 $main() {
80 +
  @entry0
81 +
    reserve %0 4 4;
82 +
    store w32 0 %0 0;
83 +
    call w64 %1 $create(20);
84 +
    reserve %2 8 8;
85 +
    store w64 %1 %2 0;
86 +
    reserve %3 8 4;
87 +
    store w32 1 %3 0;
88 +
    store w32 1 %3 4;
89 +
    reserve %4 16 8;
90 +
    store w32 20 %4 0;
91 +
    store w64 0 %4 8;
92 +
    reserve %5 4 4;
93 +
    call w32 %6 $read(%2);
94 +
    store w32 %6 %5 0;
95 +
    reserve %7 16 8;
96 +
    store w8 0 %7 0;
97 +
    add w64 %8 %7 8;
98 +
    blit %8 %5 4;
99 +
    reserve %9 16 8;
100 +
    call w64 %10 $empty(%9);
101 +
    reserve %11 16 8;
102 +
    store w8 1 %11 0;
103 +
    store w64 0 %11 8;
104 +
    call w32 %12 $itemValue(%10);
105 +
    br.eq w32 %12 0 @assert.ok2 @assert.fail1;
106 +
  @assert.fail1
107 +
    unreachable;
108 +
  @assert.ok2
109 +
    call w32 %13 $itemValue(%11);
110 +
    br.eq w32 %13 0 @assert.ok4 @assert.fail3;
111 +
  @assert.fail3
112 +
    unreachable;
113 +
  @assert.ok4
114 +
    call w32 %14 $load(%4);
115 +
    br.eq w32 %14 20 @assert.ok6 @assert.fail5;
116 +
  @assert.fail5
117 +
    unreachable;
118 +
  @assert.ok6
119 +
    reserve %15 4 4;
120 +
    store w32 22 %15 0;
121 +
    call w32 %16 $read(%15);
122 +
    br.eq w32 %16 22 @assert.ok8 @assert.fail7;
123 +
  @assert.fail7
124 +
    unreachable;
125 +
  @assert.ok8
126 +
    call w32 %17 $itemValue(%7);
127 +
    call w32 %18 $sum(%3);
128 +
    add w32 %19 %17 %18;
129 +
    load w32 %20 %4 0;
130 +
    add w32 %21 %19 %20;
131 +
    ret %21;
132 +
}
test/tests/regions.owner.freeze.rad added +15 -0
1 +
//! returns: 42
2 +
3 +
/// A uniquely owned value.
4 +
record Owner {
5 +
    /// Storage controlled by this owner.
6 +
    value: *mut u32,
7 +
}
8 +
9 +
@default fn main() -> u32 {
10 +
    static VALUE: u32 = 42;
11 +
    let owner = Owner { value: &mut VALUE };
12 +
    let case Owner { value } = owner else panic;
13 +
    let shared: *u32 = value;
14 +
    return *shared;
15 +
}
test/tests/regions.owner.freeze.ril added +21 -0
1 +
data mut $main$nominal$VALUE align 4 {
2 +
    w32 42;
3 +
}
4 +
5 +
fn w32 $main() {
6 +
  @entry0
7 +
    reserve %0 8 8;
8 +
    copy %1 $main$nominal$VALUE;
9 +
    store w64 %1 %0 0;
10 +
    reserve %2 8 8;
11 +
    blit %2 %0 8;
12 +
    jmp @success1;
13 +
  @success1
14 +
    load w64 %3 %2 0;
15 +
    jmp @merge3;
16 +
  @else2
17 +
    unreachable;
18 +
  @merge3
19 +
    load w32 %4 %3 0;
20 +
    ret %4;
21 +
}
test/tests/regions.owner.lifetime.rad added +42 -0
1 +
//! returns: 42
2 +
3 +
/// An exclusive owner of regional storage.
4 +
record Owner: 'r {
5 +
    /// Value controlled by the owner.
6 +
    value: &'r mut u32,
7 +
}
8 +
9 +
/// A copied shared reference to regional storage.
10 +
record Shared: 'r + Copy {
11 +
    /// Value that remains valid independently of this container.
12 +
    value: &'r u32,
13 +
}
14 +
15 +
/// Reborrow an exclusive field for the owner's borrow region.
16 +
fn readOwner 'r 's (owner: &'s Owner 'r) -> &'s u32 where 'r: 's {
17 +
    return &*owner.value;
18 +
}
19 +
20 +
/// Retain the region of a copyable shared field.
21 +
fn readShared 'r 's (shared: &'s Shared 'r) -> &'r u32 where 'r: 's {
22 +
    return &*shared.value;
23 +
}
24 +
25 +
@default fn main() -> u32 {
26 +
    let mut value: u32 = 41;
27 +
    let reference: 'value = &mut value in {
28 +
        let owner = Owner 'value { value: reference };
29 +
        let view: 'read = &owner where 'value: 'read in {
30 +
            let first = readOwner(view);
31 +
            assert *first == 41;
32 +
        }
33 +
        set *owner.value = 42;
34 +
        let shared = Shared 'value { value: &*owner.value };
35 +
        let mut retained: ?&'value u32 = nil;
36 +
        let view: 'copy = &shared where 'value: 'copy in {
37 +
            set retained = readShared(view);
38 +
        }
39 +
        let answer = retained else panic;
40 +
        return *answer;
41 +
    }
42 +
}
test/tests/regions.owner.lifetime.ril added +39 -0
1 +
fn w64 $readOwner(w64 %0) {
2 +
  @entry0
3 +
    load w64 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w64 $readShared(w64 %0) {
8 +
  @entry0
9 +
    load w64 %1 %0 0;
10 +
    ret %1;
11 +
}
12 +
13 +
fn w32 $main() {
14 +
  @entry0
15 +
    reserve %0 4 4;
16 +
    store w32 41 %0 0;
17 +
    reserve %1 8 8;
18 +
    store w64 %0 %1 0;
19 +
    call w64 %2 $readOwner(%1);
20 +
    load w32 %3 %2 0;
21 +
    br.eq w32 %3 41 @assert.ok2 @assert.fail1;
22 +
  @assert.fail1
23 +
    unreachable;
24 +
  @assert.ok2
25 +
    load w64 %4 %1 0;
26 +
    store w32 42 %4 0;
27 +
    reserve %5 8 8;
28 +
    load w64 %6 %1 0;
29 +
    store w64 %6 %5 0;
30 +
    call w64 %7 $readShared(%5);
31 +
    br.ne w32 %7 0 @success3 @else4;
32 +
  @success3
33 +
    jmp @merge5;
34 +
  @else4
35 +
    unreachable;
36 +
  @merge5
37 +
    load w32 %8 %7 0;
38 +
    ret %8;
39 +
}
test/tests/regions.ownership.move.rad added +3 -0
1 +
// Regional exclusive references retain affine ownership and arithmetic checks.
2 +
3 +
fn f 'r (p: &'r mut u8) { let q: &'r mut u8 = p; set *q = 3; }
test/tests/regions.ownership.move.ril added +5 -0
1 +
fn w64 $f(w64 %0) {
2 +
  @entry0
3 +
    store w8 3 %0 0;
4 +
    ret;
5 +
}
test/tests/regions.parameters.rad added +5 -0
1 +
//! Region-qualified pointer and slice parameter lowering.
2 +
3 +
fn load 'r (p: &'r u32) -> u32 { return *p; }
4 +
fn store 'r (p: &'r mut u32, value: u32) { set *p = value; }
5 +
fn element 'r (p: &'r [u32], i: u32) -> u32 { return p[i]; }
test/tests/regions.parameters.ril added +26 -0
1 +
fn w32 $load(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 0;
4 +
    ret %1;
5 +
}
6 +
7 +
fn w64 $store(w64 %0, w32 %1) {
8 +
  @entry0
9 +
    store w32 %1 %0 0;
10 +
    ret;
11 +
}
12 +
13 +
fn w32 $element(w64 %0, w32 %1) {
14 +
  @entry0
15 +
    load w32 %2 %0 8;
16 +
    br.ult w32 %1 %2 @guard#pass1 @guard#trap2;
17 +
  @guard#pass1
18 +
    load w64 %3 %0 0;
19 +
    mul w64 %4 %1 4;
20 +
    add w64 %5 %3 %4;
21 +
    load w32 %6 %5 0;
22 +
    ret %6;
23 +
  @guard#trap2
24 +
    ebreak;
25 +
    unreachable;
26 +
}
test/tests/regions.session.allocate.rad added +73 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
record Pair: Copy { a: u32, b: u32 }
7 +
record Empty: Copy {}
8 +
record Entry { value: u32 }
9 +
10 +
fn create 'r (session: &Session 'r, value: u32) -> &'r mut u32 throws (alloc::AllocError) {
11 +
    return try session.new(value);
12 +
}
13 +
14 +
fn initializer(state: &mut u32) -> u32 throws (alloc::AllocError) {
15 +
    set *state = 42;
16 +
    throw alloc::AllocError::OutOfMemory;
17 +
}
18 +
19 +
fn failedInitializer 'r (session: &Session 'r, state: &mut u32) -> &'r mut u32 throws (alloc::AllocError) {
20 +
    return try session.new(try initializer(state));
21 +
}
22 +
23 +
fn failures(arena: &mut alloc::Arena) {
24 +
    let before = alloc::used(arena);
25 +
    let mut state: u32 = 0;
26 +
    use *arena as failed in {
27 +
        try failedInitializer(&failed, &mut state) catch error as alloc::AllocError {
28 +
            assert state == 42;
29 +
        };
30 +
        let overflow = try? failed.fill(1 as u64, 4294967295);
31 +
        if let unexpected = overflow {
32 +
            panic;
33 +
        }
34 +
        try failed.fill(1 as u32, 256) catch error as alloc::AllocError {
35 +
            assert state == 42;
36 +
        };
37 +
    }
38 +
    assert alloc::used(arena) == before;
39 +
    assert state == 42;
40 +
}
41 +
42 +
@default fn main() -> u32 {
43 +
    static DATA: [u8; 256] = [0; 256];
44 +
    let mut arena = alloc::new(&mut DATA[1..]);
45 +
    failures(&mut arena);
46 +
    use arena as objects in {
47 +
        let entry = try! objects.new(Entry { value: 7 });
48 +
        assert entry.value == 7;
49 +
        let name = try! objects.new("value");
50 +
        assert name.len == 5;
51 +
        let first = try! create(&objects, 20);
52 +
        let second = try! objects.new(Pair { a: 11, b: 11 });
53 +
        let filled = try! objects.fill(Pair { a: 1, b: 2 }, 3);
54 +
        let copied = try! objects.copy(&filled[..]);
55 +
        set filled[0].a = 9;
56 +
        assert copied[0].a == 1;
57 +
        assert copied[2].b == 2;
58 +
        let copiedAgain = try! objects.copy(&filled[..] if true else &copied[..]);
59 +
        assert copiedAgain[0].a == 9;
60 +
        set filled[1].a = 5;
61 +
        assert copiedAgain[1].a == 1;
62 +
        let pointer = try! objects.new(first);
63 +
        assert **pointer == 20;
64 +
        let zero = try! objects.fill(Empty {}, 0);
65 +
        assert zero.len == 0;
66 +
        let empty = try! objects.new(Empty {});
67 +
        let many = try! objects.fill(Empty {}, 2);
68 +
        assert many.len == 2;
69 +
        assert **pointer == 20;
70 +
        assert second.a + second.b == 22;
71 +
        return **pointer + second.a + second.b;
72 +
    }
73 +
}
test/tests/regions.session.allocate.ril added +641 -0
1 +
data mut $"regions.session.allocate::regions.session.allocate::main$nominal$DATA" align 1 {
2 +
    w8 0 * 256;
3 +
}
4 +
5 +
data $"regions.session.allocate::main$literal$0" align 1 {
6 +
    str "value";
7 +
}
8 +
9 +
fn w64 $"regions.session.allocate::create"(w64 %0, w64 %1, w32 %2) {
10 +
  @entry0
11 +
    load w64 %3 %1 0;
12 +
    load w64 %4 %1 8;
13 +
    load w64 %5 %4 0;
14 +
    reserve %6 16 8;
15 +
    call w64 %7 %5(%6, %3, 4, 4);
16 +
    load w64 %8 %7 0;
17 +
    reserve %9 8 8;
18 +
    br.ne w32 %8 0 @err2 @ok1;
19 +
  @ok1
20 +
    load w64 %10 %7 8;
21 +
    store w32 %2 %10 0;
22 +
    load w64 %11 %7 8;
23 +
    store w64 %11 %9 0;
24 +
    jmp @merge3;
25 +
  @err2
26 +
    reserve %12 16 8;
27 +
    store w64 %8 %12 0;
28 +
    add w64 %13 %7 8;
29 +
    add w64 %14 %12 8;
30 +
    blit %14 %13 1;
31 +
    blit %0 %12 16;
32 +
    ret %0;
33 +
  @merge3
34 +
    load w64 %15 %9 0;
35 +
    reserve %16 16 8;
36 +
    store w64 0 %16 0;
37 +
    store w64 %15 %16 8;
38 +
    blit %0 %16 16;
39 +
    ret %0;
40 +
}
41 +
42 +
fn w64 $"regions.session.allocate::initializer"(w64 %0, w64 %1) {
43 +
  @entry0
44 +
    store w32 42 %1 0;
45 +
    reserve %2 12 8;
46 +
    store w64 1 %2 0;
47 +
    store w8 0 %2 8;
48 +
    blit %0 %2 12;
49 +
    ret %0;
50 +
}
51 +
52 +
fn w64 $"regions.session.allocate::failedInitializer"(w64 %0, w64 %1, w64 %2) {
53 +
  @entry0
54 +
    load w64 %3 %1 0;
55 +
    load w64 %4 %1 8;
56 +
    load w64 %5 %4 0;
57 +
    reserve %6 12 8;
58 +
    call w64 %7 $"regions.session.allocate::initializer"(%6, %2);
59 +
    load w64 %8 %7 0;
60 +
    reserve %9 4 4;
61 +
    br.ne w32 %8 0 @err2 @ok1;
62 +
  @ok1
63 +
    load w32 %10 %7 8;
64 +
    store w32 %10 %9 0;
65 +
    jmp @merge3;
66 +
  @err2
67 +
    reserve %11 16 8;
68 +
    store w64 %8 %11 0;
69 +
    add w64 %12 %7 8;
70 +
    add w64 %13 %11 8;
71 +
    blit %13 %12 1;
72 +
    blit %0 %11 16;
73 +
    ret %0;
74 +
  @merge3
75 +
    load w32 %14 %9 0;
76 +
    reserve %15 16 8;
77 +
    call w64 %16 %5(%15, %3, 4, 4);
78 +
    load w64 %17 %16 0;
79 +
    reserve %18 8 8;
80 +
    br.ne w32 %17 0 @err5 @ok4;
81 +
  @ok4
82 +
    load w64 %19 %16 8;
83 +
    store w32 %14 %19 0;
84 +
    load w64 %20 %16 8;
85 +
    store w64 %20 %18 0;
86 +
    jmp @merge6;
87 +
  @err5
88 +
    reserve %21 16 8;
89 +
    store w64 %17 %21 0;
90 +
    add w64 %22 %16 8;
91 +
    add w64 %23 %21 8;
92 +
    blit %23 %22 1;
93 +
    blit %0 %21 16;
94 +
    ret %0;
95 +
  @merge6
96 +
    load w64 %24 %18 0;
97 +
    reserve %25 16 8;
98 +
    store w64 0 %25 0;
99 +
    store w64 %24 %25 8;
100 +
    blit %0 %25 16;
101 +
    ret %0;
102 +
}
103 +
104 +
fn w64 $"regions.session.allocate::failures"(w64 %0) {
105 +
  @entry0
106 +
    call w32 %1 $"std::lang::alloc::used"(%0);
107 +
    reserve %2 4 4;
108 +
    store w32 0 %2 0;
109 +
    reserve %3 16 8;
110 +
    store w64 %0 %3 0;
111 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %3 8;
112 +
    reserve %4 16 8;
113 +
    call w64 %5 $"regions.session.allocate::failedInitializer"(%4, %3, %2);
114 +
    load w64 %6 %5 0;
115 +
    reserve %7 8 8;
116 +
    br.ne w32 %6 0 @err2 @ok1;
117 +
  @ok1
118 +
    load w64 %8 %5 8;
119 +
    store w64 %8 %7 0;
120 +
    jmp @merge3;
121 +
  @err2
122 +
    switch %6 (1 @catch4) @unreachable5;
123 +
  @merge3
124 +
    load w64 %11 %7 0;
125 +
    load w64 %13 %3 0;
126 +
    load w64 %14 %3 8;
127 +
    load w64 %15 %14 8;
128 +
    reserve %16 24 8;
129 +
    call w64 %17 %15(%16, %13, 8, 8, 4294967295);
130 +
    load w64 %18 %17 0;
131 +
    reserve %19 16 8;
132 +
    br.ne w32 %18 0 @err9 @ok8;
133 +
  @catch4
134 +
    load w8 %9 %5 8;
135 +
    load w32 %10 %2 0;
136 +
    br.eq w32 %10 42 @assert.ok7 @assert.fail6;
137 +
  @unreachable5
138 +
    unreachable;
139 +
  @assert.fail6
140 +
    unreachable;
141 +
  @assert.ok7
142 +
    jmp @merge3;
143 +
  @ok8
144 +
    load w64 %20 %17 8;
145 +
    jmp @fill10(0);
146 +
  @err9
147 +
    reserve %26 16 8;
148 +
    store w64 0 %26 0;
149 +
    store w32 0 %26 8;
150 +
    store w32 0 %26 12;
151 +
    blit %19 %26 16;
152 +
    jmp @merge13;
153 +
  @fill10(w32 %21)
154 +
    br.ult w32 %21 4294967295 @fill11 @fill12;
155 +
  @fill11
156 +
    mul w64 %22 %21 8;
157 +
    add w64 %23 %20 %22;
158 +
    store w64 1 %23 0;
159 +
    add w32 %24 %21 1;
160 +
    jmp @fill10(%24);
161 +
  @fill12
162 +
    add w64 %25 %17 8;
163 +
    blit %19 %25 16;
164 +
    jmp @merge13;
165 +
  @merge13
166 +
    reserve %27 16 8;
167 +
    blit %27 %19 16;
168 +
    load w64 %28 %27 0;
169 +
    br.ne w32 %28 0 @then14 @else15;
170 +
  @then14
171 +
    unreachable;
172 +
  @else15
173 +
    jmp @merge16;
174 +
  @merge16
175 +
    load w64 %31 %3 0;
176 +
    load w64 %32 %3 8;
177 +
    load w64 %33 %32 8;
178 +
    zext w32 %34 1;
179 +
    reserve %35 24 8;
180 +
    call w64 %36 %33(%35, %31, 4, 4, 256);
181 +
    load w64 %37 %36 0;
182 +
    reserve %38 16 8;
183 +
    br.ne w32 %37 0 @err18 @ok17;
184 +
  @ok17
185 +
    load w64 %39 %36 8;
186 +
    jmp @fill19(0);
187 +
  @err18
188 +
    switch %37 (1 @catch23) @unreachable24;
189 +
  @fill19(w32 %40)
190 +
    br.ult w32 %40 256 @fill20 @fill21;
191 +
  @fill20
192 +
    mul w64 %41 %40 4;
193 +
    add w64 %42 %39 %41;
194 +
    store w32 %34 %42 0;
195 +
    add w32 %43 %40 1;
196 +
    jmp @fill19(%43);
197 +
  @fill21
198 +
    add w64 %44 %36 8;
199 +
    blit %38 %44 16;
200 +
    jmp @merge22;
201 +
  @merge22
202 +
    call w32 %55 $"std::lang::alloc::used"(%0);
203 +
    br.eq w32 %55 %1 @assert.ok28 @assert.fail27;
204 +
  @catch23
205 +
    load w8 %45 %36 8;
206 +
    load w32 %49 %2 0;
207 +
    br.eq w32 %49 42 @assert.ok26 @assert.fail25;
208 +
  @unreachable24
209 +
    unreachable;
210 +
  @assert.fail25
211 +
    unreachable;
212 +
  @assert.ok26
213 +
    jmp @merge22;
214 +
  @assert.fail27
215 +
    unreachable;
216 +
  @assert.ok28
217 +
    load w32 %63 %2 0;
218 +
    br.eq w32 %63 42 @assert.ok30 @assert.fail29;
219 +
  @assert.fail29
220 +
    unreachable;
221 +
  @assert.ok30
222 +
    ret;
223 +
}
224 +
225 +
fn w32 $"regions.session.allocate::main"() {
226 +
  @entry0
227 +
    copy %0 $"regions.session.allocate::regions.session.allocate::main$nominal$DATA";
228 +
    add w64 %1 %0 1;
229 +
    sub w32 %2 256 1;
230 +
    reserve %3 16 8;
231 +
    store w64 %1 %3 0;
232 +
    store w32 %2 %3 8;
233 +
    store w32 %2 %3 12;
234 +
    reserve %4 24 8;
235 +
    call w64 %5 $"std::lang::alloc::new"(%4, %3);
236 +
    call w64 $"regions.session.allocate::failures"(%5);
237 +
    reserve %6 16 8;
238 +
    store w64 %5 %6 0;
239 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %6 8;
240 +
    load w64 %7 %6 0;
241 +
    load w64 %8 %6 8;
242 +
    load w64 %9 %8 0;
243 +
    reserve %10 4 4;
244 +
    store w32 7 %10 0;
245 +
    reserve %11 16 8;
246 +
    call w64 %12 %9(%11, %7, 4, 4);
247 +
    load w64 %13 %12 0;
248 +
    reserve %14 8 8;
249 +
    br.ne w32 %13 0 @err2 @ok1;
250 +
  @ok1
251 +
    load w64 %15 %12 8;
252 +
    blit %15 %10 4;
253 +
    load w64 %16 %12 8;
254 +
    store w64 %16 %14 0;
255 +
    jmp @merge3;
256 +
  @err2
257 +
    unreachable;
258 +
  @merge3
259 +
    load w64 %17 %14 0;
260 +
    load w32 %18 %17 0;
261 +
    br.eq w32 %18 7 @assert.ok5 @assert.fail4;
262 +
  @assert.fail4
263 +
    unreachable;
264 +
  @assert.ok5
265 +
    load w64 %19 %6 0;
266 +
    load w64 %20 %6 8;
267 +
    load w64 %21 %20 0;
268 +
    copy %22 $"regions.session.allocate::main$literal$0";
269 +
    reserve %23 16 8;
270 +
    store w64 %22 %23 0;
271 +
    store w32 5 %23 8;
272 +
    store w32 5 %23 12;
273 +
    reserve %24 16 8;
274 +
    call w64 %25 %21(%24, %19, 16, 8);
275 +
    load w64 %26 %25 0;
276 +
    reserve %27 8 8;
277 +
    br.ne w32 %26 0 @err7 @ok6;
278 +
  @ok6
279 +
    load w64 %28 %25 8;
280 +
    blit %28 %23 16;
281 +
    load w64 %29 %25 8;
282 +
    store w64 %29 %27 0;
283 +
    jmp @merge8;
284 +
  @err7
285 +
    unreachable;
286 +
  @merge8
287 +
    load w64 %30 %27 0;
288 +
    load w32 %31 %30 8;
289 +
    br.eq w32 %31 5 @assert.ok10 @assert.fail9;
290 +
  @assert.fail9
291 +
    unreachable;
292 +
  @assert.ok10
293 +
    reserve %32 16 8;
294 +
    call w64 %33 $"regions.session.allocate::create"(%32, %6, 20);
295 +
    load w64 %34 %33 0;
296 +
    reserve %35 8 8;
297 +
    br.ne w32 %34 0 @err12 @ok11;
298 +
  @ok11
299 +
    load w64 %36 %33 8;
300 +
    store w64 %36 %35 0;
301 +
    jmp @merge13;
302 +
  @err12
303 +
    unreachable;
304 +
  @merge13
305 +
    load w64 %37 %35 0;
306 +
    load w64 %38 %6 0;
307 +
    load w64 %39 %6 8;
308 +
    load w64 %40 %39 0;
309 +
    reserve %41 8 4;
310 +
    store w32 11 %41 0;
311 +
    store w32 11 %41 4;
312 +
    reserve %42 16 8;
313 +
    call w64 %43 %40(%42, %38, 8, 4);
314 +
    load w64 %44 %43 0;
315 +
    reserve %45 8 8;
316 +
    br.ne w32 %44 0 @err15 @ok14;
317 +
  @ok14
318 +
    load w64 %46 %43 8;
319 +
    blit %46 %41 8;
320 +
    load w64 %47 %43 8;
321 +
    store w64 %47 %45 0;
322 +
    jmp @merge16;
323 +
  @err15
324 +
    unreachable;
325 +
  @merge16
326 +
    load w64 %48 %45 0;
327 +
    load w64 %49 %6 0;
328 +
    load w64 %50 %6 8;
329 +
    load w64 %51 %50 8;
330 +
    reserve %52 8 4;
331 +
    store w32 1 %52 0;
332 +
    store w32 2 %52 4;
333 +
    reserve %53 24 8;
334 +
    call w64 %54 %51(%53, %49, 8, 4, 3);
335 +
    load w64 %55 %54 0;
336 +
    reserve %56 16 8;
337 +
    br.ne w32 %55 0 @err18 @ok17;
338 +
  @ok17
339 +
    load w64 %57 %54 8;
340 +
    jmp @fill19(0);
341 +
  @err18
342 +
    unreachable;
343 +
  @fill19(w32 %58)
344 +
    br.ult w32 %58 3 @fill20 @fill21;
345 +
  @fill20
346 +
    mul w64 %59 %58 8;
347 +
    add w64 %60 %57 %59;
348 +
    blit %60 %52 8;
349 +
    add w32 %61 %58 1;
350 +
    jmp @fill19(%61);
351 +
  @fill21
352 +
    add w64 %62 %54 8;
353 +
    blit %56 %62 16;
354 +
    jmp @merge22;
355 +
  @merge22
356 +
    load w64 %64 %6 0;
357 +
    load w64 %65 %6 8;
358 +
    load w64 %66 %65 8;
359 +
    load w64 %67 %56 0;
360 +
    load w32 %68 %56 8;
361 +
    reserve %69 16 8;
362 +
    store w64 %67 %69 0;
363 +
    store w32 %68 %69 8;
364 +
    store w32 %68 %69 12;
365 +
    load w32 %70 %69 8;
366 +
    reserve %71 24 8;
367 +
    call w64 %72 %66(%71, %64, 8, 4, %70);
368 +
    load w64 %73 %72 0;
369 +
    reserve %74 16 8;
370 +
    br.ne w32 %73 0 @err24 @ok23;
371 +
  @ok23
372 +
    load w64 %75 %72 8;
373 +
    load w64 %76 %69 0;
374 +
    mul w32 %77 %70 8;
375 +
    jmp @allocate.copy25(0);
376 +
  @err24
377 +
    unreachable;
378 +
  @allocate.copy25(w32 %78)
379 +
    br.ult w32 %78 %77 @allocate.copy26 @allocate.copy27;
380 +
  @allocate.copy26
381 +
    add w64 %79 %76 %78;
382 +
    load w8 %80 %79 0;
383 +
    add w64 %81 %75 %78;
384 +
    store w8 %80 %81 0;
385 +
    add w32 %82 %78 1;
386 +
    jmp @allocate.copy25(%82);
387 +
  @allocate.copy27
388 +
    add w64 %83 %72 8;
389 +
    blit %74 %83 16;
390 +
    jmp @merge28;
391 +
  @merge28
392 +
    load w32 %85 %56 8;
393 +
    br.ult w32 0 %85 @guard#pass29 @guard#trap30;
394 +
  @guard#pass29
395 +
    load w64 %86 %56 0;
396 +
    store w32 9 %86 0;
397 +
    load w32 %87 %74 8;
398 +
    br.ult w32 0 %87 @guard#pass33 @guard#trap34;
399 +
  @guard#trap30
400 +
    ebreak;
401 +
    unreachable;
402 +
  @assert.fail31
403 +
    unreachable;
404 +
  @assert.ok32
405 +
    load w32 %90 %74 8;
406 +
    br.ult w32 2 %90 @guard#pass37 @guard#trap38;
407 +
  @guard#pass33
408 +
    load w64 %88 %74 0;
409 +
    load w32 %89 %88 0;
410 +
    br.eq w32 %89 1 @assert.ok32 @assert.fail31;
411 +
  @guard#trap34
412 +
    ebreak;
413 +
    unreachable;
414 +
  @assert.fail35
415 +
    unreachable;
416 +
  @assert.ok36
417 +
    load w64 %96 %6 0;
418 +
    load w64 %97 %6 8;
419 +
    load w64 %98 %97 8;
420 +
    reserve %99 16 8;
421 +
    copy %100 1;
422 +
    br.ne w32 %100 0 @cond#then39 @cond#else40;
423 +
  @guard#pass37
424 +
    load w64 %91 %74 0;
425 +
    mul w64 %92 2 8;
426 +
    add w64 %93 %91 %92;
427 +
    load w32 %94 %93 4;
428 +
    br.eq w32 %94 2 @assert.ok36 @assert.fail35;
429 +
  @guard#trap38
430 +
    ebreak;
431 +
    unreachable;
432 +
  @cond#then39
433 +
    load w64 %101 %56 0;
434 +
    load w32 %102 %56 8;
435 +
    reserve %103 16 8;
436 +
    store w64 %101 %103 0;
437 +
    store w32 %102 %103 8;
438 +
    store w32 %102 %103 12;
439 +
    blit %99 %103 16;
440 +
    jmp @cond#merge41;
441 +
  @cond#else40
442 +
    load w64 %104 %74 0;
443 +
    load w32 %105 %74 8;
444 +
    reserve %106 16 8;
445 +
    store w64 %104 %106 0;
446 +
    store w32 %105 %106 8;
447 +
    store w32 %105 %106 12;
448 +
    blit %99 %106 16;
449 +
    jmp @cond#merge41;
450 +
  @cond#merge41
451 +
    load w32 %107 %99 8;
452 +
    reserve %108 24 8;
453 +
    call w64 %109 %98(%108, %96, 8, 4, %107);
454 +
    load w64 %110 %109 0;
455 +
    reserve %111 16 8;
456 +
    br.ne w32 %110 0 @err43 @ok42;
457 +
  @ok42
458 +
    load w64 %112 %109 8;
459 +
    load w64 %113 %99 0;
460 +
    mul w32 %114 %107 8;
461 +
    jmp @allocate.copy44(0);
462 +
  @err43
463 +
    unreachable;
464 +
  @allocate.copy44(w32 %115)
465 +
    br.ult w32 %115 %114 @allocate.copy45 @allocate.copy46;
466 +
  @allocate.copy45
467 +
    add w64 %116 %113 %115;
468 +
    load w8 %117 %116 0;
469 +
    add w64 %118 %112 %115;
470 +
    store w8 %117 %118 0;
471 +
    add w32 %119 %115 1;
472 +
    jmp @allocate.copy44(%119);
473 +
  @allocate.copy46
474 +
    add w64 %120 %109 8;
475 +
    blit %111 %120 16;
476 +
    jmp @merge47;
477 +
  @merge47
478 +
    load w32 %121 %111 8;
479 +
    br.ult w32 0 %121 @guard#pass50 @guard#trap51;
480 +
  @assert.fail48
481 +
    unreachable;
482 +
  @assert.ok49
483 +
    load w32 %126 %56 8;
484 +
    br.ult w32 1 %126 @guard#pass52 @guard#trap53;
485 +
  @guard#pass50
486 +
    load w64 %122 %111 0;
487 +
    load w32 %123 %122 0;
488 +
    br.eq w32 %123 9 @assert.ok49 @assert.fail48;
489 +
  @guard#trap51
490 +
    ebreak;
491 +
    unreachable;
492 +
  @guard#pass52
493 +
    load w64 %127 %56 0;
494 +
    mul w64 %128 1 8;
495 +
    add w64 %129 %127 %128;
496 +
    store w32 5 %129 0;
497 +
    load w32 %130 %111 8;
498 +
    br.ult w32 1 %130 @guard#pass56 @guard#trap57;
499 +
  @guard#trap53
500 +
    ebreak;
501 +
    unreachable;
502 +
  @assert.fail54
503 +
    unreachable;
504 +
  @assert.ok55
505 +
    load w64 %137 %6 0;
506 +
    load w64 %138 %6 8;
507 +
    load w64 %139 %138 0;
508 +
    reserve %144 16 8;
509 +
    call w64 %145 %139(%144, %137, 8, 8);
510 +
    load w64 %146 %145 0;
511 +
    reserve %147 8 8;
512 +
    br.ne w32 %146 0 @err59 @ok58;
513 +
  @guard#pass56
514 +
    load w64 %131 %111 0;
515 +
    mul w64 %132 1 8;
516 +
    add w64 %133 %131 %132;
517 +
    load w32 %134 %133 0;
518 +
    br.eq w32 %134 1 @assert.ok55 @assert.fail54;
519 +
  @guard#trap57
520 +
    ebreak;
521 +
    unreachable;
522 +
  @ok58
523 +
    load w64 %148 %145 8;
524 +
    store w64 %37 %148 0;
525 +
    load w64 %149 %145 8;
526 +
    store w64 %149 %147 0;
527 +
    jmp @merge60;
528 +
  @err59
529 +
    unreachable;
530 +
  @merge60
531 +
    load w64 %150 %147 0;
532 +
    load w64 %151 %150 0;
533 +
    load w32 %152 %151 0;
534 +
    br.eq w32 %152 20 @assert.ok62 @assert.fail61;
535 +
  @assert.fail61
536 +
    unreachable;
537 +
  @assert.ok62
538 +
    load w64 %153 %6 0;
539 +
    load w64 %154 %6 8;
540 +
    load w64 %155 %154 8;
541 +
    reserve %156 0 1;
542 +
    reserve %157 24 8;
543 +
    call w64 %158 %155(%157, %153, 1, 1, 0);
544 +
    load w64 %159 %158 0;
545 +
    reserve %160 16 8;
546 +
    br.ne w32 %159 0 @err64 @ok63;
547 +
  @ok63
548 +
    load w64 %161 %158 8;
549 +
    jmp @fill65(0);
550 +
  @err64
551 +
    unreachable;
552 +
  @fill65(w32 %162)
553 +
    br.ult w32 %162 0 @fill66 @fill67;
554 +
  @fill66
555 +
    mul w64 %163 %162 0;
556 +
    add w64 %164 %161 %163;
557 +
    blit %164 %156 0;
558 +
    add w32 %165 %162 1;
559 +
    jmp @fill65(%165);
560 +
  @fill67
561 +
    add w64 %166 %158 8;
562 +
    blit %160 %166 16;
563 +
    jmp @merge68;
564 +
  @merge68
565 +
    load w32 %167 %160 8;
566 +
    br.eq w32 %167 0 @assert.ok70 @assert.fail69;
567 +
  @assert.fail69
568 +
    unreachable;
569 +
  @assert.ok70
570 +
    load w64 %169 %6 0;
571 +
    load w64 %170 %6 8;
572 +
    load w64 %171 %170 0;
573 +
    reserve %172 0 1;
574 +
    reserve %173 16 8;
575 +
    call w64 %174 %171(%173, %169, 1, 1);
576 +
    load w64 %175 %174 0;
577 +
    reserve %176 8 8;
578 +
    br.ne w32 %175 0 @err72 @ok71;
579 +
  @ok71
580 +
    load w64 %177 %174 8;
581 +
    blit %177 %172 0;
582 +
    load w64 %178 %174 8;
583 +
    store w64 %178 %176 0;
584 +
    jmp @merge73;
585 +
  @err72
586 +
    unreachable;
587 +
  @merge73
588 +
    load w64 %179 %176 0;
589 +
    load w64 %180 %6 0;
590 +
    load w64 %181 %6 8;
591 +
    load w64 %182 %181 8;
592 +
    reserve %183 0 1;
593 +
    reserve %184 24 8;
594 +
    call w64 %185 %182(%184, %180, 1, 1, 2);
595 +
    load w64 %186 %185 0;
596 +
    reserve %187 16 8;
597 +
    br.ne w32 %186 0 @err75 @ok74;
598 +
  @ok74
599 +
    load w64 %188 %185 8;
600 +
    jmp @fill76(0);
601 +
  @err75
602 +
    unreachable;
603 +
  @fill76(w32 %189)
604 +
    br.ult w32 %189 2 @fill77 @fill78;
605 +
  @fill77
606 +
    mul w64 %190 %189 0;
607 +
    add w64 %191 %188 %190;
608 +
    blit %191 %183 0;
609 +
    add w32 %192 %189 1;
610 +
    jmp @fill76(%192);
611 +
  @fill78
612 +
    add w64 %193 %185 8;
613 +
    blit %187 %193 16;
614 +
    jmp @merge79;
615 +
  @merge79
616 +
    load w32 %194 %187 8;
617 +
    br.eq w32 %194 2 @assert.ok81 @assert.fail80;
618 +
  @assert.fail80
619 +
    unreachable;
620 +
  @assert.ok81
621 +
    load w64 %197 %150 0;
622 +
    load w32 %198 %197 0;
623 +
    br.eq w32 %198 20 @assert.ok83 @assert.fail82;
624 +
  @assert.fail82
625 +
    unreachable;
626 +
  @assert.ok83
627 +
    load w32 %205 %48 0;
628 +
    load w32 %206 %48 4;
629 +
    add w32 %207 %205 %206;
630 +
    br.eq w32 %207 22 @assert.ok85 @assert.fail84;
631 +
  @assert.fail84
632 +
    unreachable;
633 +
  @assert.ok85
634 +
    load w64 %208 %150 0;
635 +
    load w32 %209 %208 0;
636 +
    load w32 %210 %48 0;
637 +
    add w32 %211 %209 %210;
638 +
    load w32 %212 %48 4;
639 +
    add w32 %213 %211 %212;
640 +
    ret %213;
641 +
}
test/tests/regions.session.allocator.rad added +39 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
/// Allocation session provider that delegates to an arena.
7 +
record Allocator: 'r {
8 +
    /// Arena that owns the reserved storage.
9 +
    arena: &'r mut alloc::Arena,
10 +
}
11 +
12 +
instance alloc::Alloc for Allocator 'r {
13 +
    /// Reserve one object in the delegated arena.
14 +
    unsafe fn (self: &mut Allocator 'r) reserve(size: u32, alignment: u32) -> *unsafe mut opaque throws (alloc::AllocError) {
15 +
        return try alloc::allocRaw(self.arena, size, alignment);
16 +
    }
17 +
18 +
    /// Reserve a slice in the delegated arena.
19 +
    unsafe fn (self: &mut Allocator 'r) reserveSlice(size: u32, alignment: u32, count: u32) -> *unsafe mut [opaque] throws (alloc::AllocError) {
20 +
        return try alloc::allocRawSlice(self.arena, size, alignment, count);
21 +
    }
22 +
}
23 +
24 +
/// Allocate through a regional allocation trait implementation.
25 +
fn allocate 'r (arena: &'r mut alloc::Arena) -> u32 {
26 +
    let mut allocator = Allocator 'r { arena };
27 +
    use allocator as objects in {
28 +
        let value = try! objects.new(42 as u32);
29 +
        return *value;
30 +
    }
31 +
}
32 +
33 +
@default fn main() -> u32 {
34 +
    static DATA: [u8; 64] = [0; 64];
35 +
    let mut arena = alloc::new(&mut DATA[..]);
36 +
    let storage: 'storage = &mut arena in {
37 +
        return allocate(storage);
38 +
    }
39 +
}
test/tests/regions.session.context.rad added +78 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
/// Immutable node in one allocation region.
7 +
record Node: 'r + Copy {
8 +
    value: u32,
9 +
    next: ?&'r Node 'r,
10 +
}
11 +
12 +
/// Graph builder that owns its allocation interface.
13 +
record Context: 'r {
14 +
    storage: Session 'r,
15 +
    head: ?&'r Node 'r,
16 +
}
17 +
18 +
/// Construct a graph builder from its allocation interface.
19 +
fn context 'r (storage: Session 'r) -> Context 'r {
20 +
    return Context 'r { storage, head: nil };
21 +
}
22 +
23 +
/// Move a graph builder with all of its existing node references.
24 +
fn transfer 'r (value: Context 'r) -> Context 'r {
25 +
    return value;
26 +
}
27 +
28 +
/// Prepend one initialized node to the graph.
29 +
fn prepend 'r (self: &mut Context 'r, value: u32) {
30 +
    let node = try! self.storage.new(Node 'r { value, next: self.head });
31 +
    set self.head = node;
32 +
}
33 +
34 +
/// Sum the immutable nodes retained by the graph builder.
35 +
fn sum 'r (self: &Context 'r) -> u32 {
36 +
    let mut cursor = self.head;
37 +
    let mut result: u32 = 0;
38 +
    while let node = cursor {
39 +
        set result += node.value;
40 +
        set cursor = node.next;
41 +
    }
42 +
    return result;
43 +
}
44 +
45 +
/// Retain copied references after replacing their optional containers.
46 +
fn checkCopiedPatterns 'r (self: &Context 'r) {
47 +
    let mut current = self.head;
48 +
    if let node = current {
49 +
        set current = nil;
50 +
        assert node.value == 22;
51 +
    }
52 +
    set current = self.head;
53 +
    match current {
54 +
        case nil => {
55 +
        },
56 +
        node => {
57 +
            set current = nil;
58 +
            assert node.value == 22;
59 +
        },
60 +
    }
61 +
    assert current == nil;
62 +
}
63 +
64 +
@default unsafe fn main() -> u32 {
65 +
    static DATA: [u8; 1024] = [0; 1024];
66 +
    let mut arena = alloc::new(&mut DATA[..]);
67 +
    let mut result: u32 = 0;
68 +
    use arena as graph in {
69 +
        let mut first = context(graph);
70 +
        prepend(&mut first, 20);
71 +
        let mut moved = transfer(first);
72 +
        prepend(&mut moved, 22);
73 +
        checkCopiedPatterns(&moved);
74 +
        set result = sum(&moved);
75 +
    }
76 +
    alloc::reset(&mut arena);
77 +
    return result;
78 +
}
test/tests/regions.session.context.ril added +122 -0
1 +
data mut $"regions.session.context::regions.session.context::main$nominal$DATA" align 1 {
2 +
    w8 0 * 1024;
3 +
}
4 +
5 +
fn w64 $"regions.session.context::context"(w64 %0, w64 %1) {
6 +
  @entry0
7 +
    reserve %2 24 8;
8 +
    blit %2 %1 16;
9 +
    store w64 0 %2 16;
10 +
    blit %0 %2 24;
11 +
    ret %0;
12 +
}
13 +
14 +
fn w64 $"regions.session.context::transfer"(w64 %0, w64 %1) {
15 +
  @entry0
16 +
    blit %0 %1 24;
17 +
    ret %0;
18 +
}
19 +
20 +
fn w64 $"regions.session.context::prepend"(w64 %0, w32 %1) {
21 +
  @entry0
22 +
    load w64 %2 %0 0;
23 +
    load w64 %3 %0 8;
24 +
    load w64 %4 %3 0;
25 +
    reserve %5 16 8;
26 +
    store w32 %1 %5 0;
27 +
    load w64 %6 %0 16;
28 +
    store w64 %6 %5 8;
29 +
    reserve %7 16 8;
30 +
    call w64 %8 %4(%7, %2, 16, 8);
31 +
    load w64 %9 %8 0;
32 +
    reserve %10 8 8;
33 +
    br.ne w32 %9 0 @err2 @ok1;
34 +
  @ok1
35 +
    load w64 %11 %8 8;
36 +
    blit %11 %5 16;
37 +
    load w64 %12 %8 8;
38 +
    store w64 %12 %10 0;
39 +
    jmp @merge3;
40 +
  @err2
41 +
    unreachable;
42 +
  @merge3
43 +
    load w64 %13 %10 0;
44 +
    store w64 %13 %0 16;
45 +
    ret;
46 +
}
47 +
48 +
fn w32 $"regions.session.context::sum"(w64 %0) {
49 +
  @entry0
50 +
    load w64 %1 %0 16;
51 +
    jmp @while1(%1, 0);
52 +
  @while1(w64 %2, w32 %3)
53 +
    br.ne w32 %2 0 @body2 @merge3;
54 +
  @body2
55 +
    load w32 %4 %2 0;
56 +
    add w32 %5 %3 %4;
57 +
    load w64 %6 %2 8;
58 +
    jmp @while1(%6, %5);
59 +
  @merge3
60 +
    ret %3;
61 +
}
62 +
63 +
fn w64 $"regions.session.context::checkCopiedPatterns"(w64 %0) {
64 +
  @entry0
65 +
    load w64 %1 %0 16;
66 +
    br.ne w32 %1 0 @then1 @else2;
67 +
  @then1
68 +
    load w32 %2 %1 0;
69 +
    br.eq w32 %2 22 @assert.ok4 @assert.fail3;
70 +
  @else2
71 +
    jmp @merge5;
72 +
  @assert.fail3
73 +
    unreachable;
74 +
  @assert.ok4
75 +
    jmp @merge5;
76 +
  @merge5
77 +
    load w64 %4 %0 16;
78 +
    jmp @arm6;
79 +
  @arm6
80 +
    br.eq w64 %4 0 @case7 @arm8;
81 +
  @case7
82 +
    jmp @merge9(%4);
83 +
  @arm8
84 +
    jmp @case10;
85 +
  @merge9(w64 %6)
86 +
    br.eq w64 %6 0 @assert.ok15 @assert.fail14;
87 +
  @case10
88 +
    load w32 %5 %4 0;
89 +
    br.eq w32 %5 22 @assert.ok13 @assert.fail12;
90 +
  @assert.fail12
91 +
    unreachable;
92 +
  @assert.ok13
93 +
    jmp @merge9(0);
94 +
  @assert.fail14
95 +
    unreachable;
96 +
  @assert.ok15
97 +
    ret;
98 +
}
99 +
100 +
fn w32 $"regions.session.context::main"() {
101 +
  @entry0
102 +
    copy %0 $"regions.session.context::regions.session.context::main$nominal$DATA";
103 +
    reserve %1 16 8;
104 +
    store w64 %0 %1 0;
105 +
    store w32 1024 %1 8;
106 +
    store w32 1024 %1 12;
107 +
    reserve %2 24 8;
108 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
109 +
    reserve %4 16 8;
110 +
    store w64 %3 %4 0;
111 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
112 +
    reserve %5 24 8;
113 +
    call w64 %6 $"regions.session.context::context"(%5, %4);
114 +
    call w64 $"regions.session.context::prepend"(%6, 20);
115 +
    reserve %7 24 8;
116 +
    call w64 %8 $"regions.session.context::transfer"(%7, %6);
117 +
    call w64 $"regions.session.context::prepend"(%8, 22);
118 +
    call w64 $"regions.session.context::checkCopiedPatterns"(%8);
119 +
    call w32 %9 $"regions.session.context::sum"(%8);
120 +
    call w64 $"std::lang::alloc::reset"(%3);
121 +
    ret %9;
122 +
}
test/tests/regions.session.scope.rad added +29 -0
1 +
//! returns: 42
2 +
//! session-support
3 +
4 +
use std::lang::alloc;
5 +
6 +
fn observe 'r (session: &Session 'r) -> u32 { return 42; }
7 +
fn relay 'r (session: Session 'r) -> Session 'r { return session; }
8 +
9 +
@default fn main() -> u32 {
10 +
    static DATA: [u8; 64] = [0; 64];
11 +
    let mut arena = alloc::new(&mut DATA[..]);
12 +
    use arena as objects in {
13 +
        assert observe(&objects) == 42;
14 +
        let moved = relay(objects);
15 +
        assert observe(&moved) == 42;
16 +
    }
17 +
    alloc::reset(&mut arena);
18 +
    for i in 0..2 {
19 +
        use arena as iteration in {
20 +
            assert observe(&iteration) == 42;
21 +
            if i == 0 {
22 +
                continue;
23 +
            }
24 +
            break;
25 +
        }
26 +
    }
27 +
    alloc::reset(&mut arena);
28 +
    return 42;
29 +
}
test/tests/regions.session.scope.ril added +64 -0
1 +
data mut $"regions.session.scope::regions.session.scope::main$nominal$DATA" align 1 {
2 +
    w8 0 * 64;
3 +
}
4 +
5 +
fn w32 $"regions.session.scope::observe"(w64 %0) {
6 +
  @entry0
7 +
    ret 42;
8 +
}
9 +
10 +
fn w64 $"regions.session.scope::relay"(w64 %0, w64 %1) {
11 +
  @entry0
12 +
    blit %0 %1 16;
13 +
    ret %0;
14 +
}
15 +
16 +
fn w32 $"regions.session.scope::main"() {
17 +
  @entry0
18 +
    copy %0 $"regions.session.scope::regions.session.scope::main$nominal$DATA";
19 +
    reserve %1 16 8;
20 +
    store w64 %0 %1 0;
21 +
    store w32 64 %1 8;
22 +
    store w32 64 %1 12;
23 +
    reserve %2 24 8;
24 +
    call w64 %3 $"std::lang::alloc::new"(%2, %1);
25 +
    reserve %4 16 8;
26 +
    store w64 %3 %4 0;
27 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %4 8;
28 +
    call w32 %5 $"regions.session.scope::observe"(%4);
29 +
    br.eq w32 %5 42 @assert.ok2 @assert.fail1;
30 +
  @assert.fail1
31 +
    unreachable;
32 +
  @assert.ok2
33 +
    reserve %6 16 8;
34 +
    call w64 %7 $"regions.session.scope::relay"(%6, %4);
35 +
    call w32 %8 $"regions.session.scope::observe"(%7);
36 +
    br.eq w32 %8 42 @assert.ok4 @assert.fail3;
37 +
  @assert.fail3
38 +
    unreachable;
39 +
  @assert.ok4
40 +
    call w64 $"std::lang::alloc::reset"(%3);
41 +
    jmp @loop5(0, %3);
42 +
  @loop5(w64 %9, w64 %10)
43 +
    br.slt w64 %9 2 @body6 @merge7;
44 +
  @body6
45 +
    reserve %11 16 8;
46 +
    store w64 %10 %11 0;
47 +
    store w64 $"std::lang::alloc::vtable::Arena::Alloc" %11 8;
48 +
    call w32 %12 $"regions.session.scope::observe"(%11);
49 +
    br.eq w32 %12 42 @assert.ok9 @assert.fail8;
50 +
  @merge7
51 +
    call w64 $"std::lang::alloc::reset"(%10);
52 +
    ret 42;
53 +
  @assert.fail8
54 +
    unreachable;
55 +
  @assert.ok9
56 +
    br.eq w64 %9 0 @then10 @merge11;
57 +
  @then10
58 +
    jmp @step12;
59 +
  @merge11
60 +
    jmp @merge7;
61 +
  @step12
62 +
    add w64 %13 %9 1;
63 +
    jmp @loop5(%13, %10);
64 +
}
test/tests/regions.shared.owner.rad added +39 -0
1 +
//! returns: 42
2 +
3 +
/// An owner of an exclusive slice.
4 +
record Holder: 'r {
5 +
    /// Slice whose elements can be read through a shared holder.
6 +
    items: &'r mut [u32],
7 +
}
8 +
9 +
/// Read through a shared borrow of an exclusive owner.
10 +
fn sum 'r (holder: &Holder 'r) -> u32 {
11 +
    return holder.items[0] + holder.items[1];
12 +
}
13 +
14 +
/// Update an element through an exclusive borrow of its owner.
15 +
fn update 'r (holder: &mut Holder 'r, value: u32) {
16 +
    set holder.items[0] = value;
17 +
}
18 +
19 +
/// Reborrow an exclusive slice while retaining its owner.
20 +
fn updateSlice(items: &mut [u32], value: u32) {
21 +
    set items[1] = value;
22 +
}
23 +
24 +
/// Use a stored exclusive handle through exclusive aggregate access.
25 +
fn updateSecond 'r (holder: &mut Holder 'r, value: u32) {
26 +
    updateSlice(holder.items, value);
27 +
}
28 +
29 +
@default fn main() -> u32 {
30 +
    let mut values: [u32; 2] = [20, 22];
31 +
    let items: 'items = &mut values[..] in {
32 +
        let mut holder = Holder 'items { items };
33 +
        assert sum(&holder) == 42;
34 +
        update(&mut holder, 19);
35 +
        assert sum(&holder) == 41;
36 +
        updateSecond(&mut holder, 23);
37 +
        return sum(&holder);
38 +
    }
39 +
}
test/tests/regions.shared.owner.ril added +86 -0
1 +
fn w32 $sum(w64 %0) {
2 +
  @entry0
3 +
    load w32 %1 %0 8;
4 +
    br.ult w32 0 %1 @guard#pass1 @guard#trap2;
5 +
  @guard#pass1
6 +
    load w64 %2 %0 0;
7 +
    load w32 %3 %2 0;
8 +
    load w32 %4 %0 8;
9 +
    br.ult w32 1 %4 @guard#pass3 @guard#trap4;
10 +
  @guard#trap2
11 +
    ebreak;
12 +
    unreachable;
13 +
  @guard#pass3
14 +
    load w64 %5 %0 0;
15 +
    mul w64 %6 1 4;
16 +
    add w64 %7 %5 %6;
17 +
    load w32 %8 %7 0;
18 +
    add w32 %9 %3 %8;
19 +
    ret %9;
20 +
  @guard#trap4
21 +
    ebreak;
22 +
    unreachable;
23 +
}
24 +
25 +
fn w64 $update(w64 %0, w32 %1) {
26 +
  @entry0
27 +
    load w32 %2 %0 8;
28 +
    br.ult w32 0 %2 @guard#pass1 @guard#trap2;
29 +
  @guard#pass1
30 +
    load w64 %3 %0 0;
31 +
    store w32 %1 %3 0;
32 +
    ret;
33 +
  @guard#trap2
34 +
    ebreak;
35 +
    unreachable;
36 +
}
37 +
38 +
fn w64 $updateSlice(w64 %0, w32 %1) {
39 +
  @entry0
40 +
    load w32 %2 %0 8;
41 +
    br.ult w32 1 %2 @guard#pass1 @guard#trap2;
42 +
  @guard#pass1
43 +
    load w64 %3 %0 0;
44 +
    mul w64 %4 1 4;
45 +
    add w64 %5 %3 %4;
46 +
    store w32 %1 %5 0;
47 +
    ret;
48 +
  @guard#trap2
49 +
    ebreak;
50 +
    unreachable;
51 +
}
52 +
53 +
fn w64 $updateSecond(w64 %0, w32 %1) {
54 +
  @entry0
55 +
    reserve %2 16 8;
56 +
    blit %2 %0 16;
57 +
    call w64 $updateSlice(%2, %1);
58 +
    ret;
59 +
}
60 +
61 +
fn w32 $main() {
62 +
  @entry0
63 +
    reserve %0 8 4;
64 +
    store w32 20 %0 0;
65 +
    store w32 22 %0 4;
66 +
    reserve %1 16 8;
67 +
    store w64 %0 %1 0;
68 +
    store w32 2 %1 8;
69 +
    store w32 2 %1 12;
70 +
    reserve %2 16 8;
71 +
    blit %2 %1 16;
72 +
    call w32 %3 $sum(%2);
73 +
    br.eq w32 %3 42 @assert.ok2 @assert.fail1;
74 +
  @assert.fail1
75 +
    unreachable;
76 +
  @assert.ok2
77 +
    call w64 $update(%2, 19);
78 +
    call w32 %4 $sum(%2);
79 +
    br.eq w32 %4 41 @assert.ok4 @assert.fail3;
80 +
  @assert.fail3
81 +
    unreachable;
82 +
  @assert.ok4
83 +
    call w64 $updateSecond(%2, 23);
84 +
    call w32 %5 $sum(%2);
85 +
    ret %5;
86 +
}
test/tests/regions.storage.rad added +75 -0
1 +
//! returns: 42
2 +
3 +
record Reader: 'r + Copy { value: &'r u32 }
4 +
record Writer: 'r { value: &'r mut u32 }
5 +
union View: 'r + Copy { Item { value: &'r u32 }, Empty }
6 +
record Error: 'r + Copy { value: &'r u32 }
7 +
union Other: Copy { Failed }
8 +
9 +
fn reader 'r (p: &'r u32) -> Reader 'r { return Reader { value: p }; }
10 +
fn writer 'r (p: &'r mut u32) -> Writer 'r { return Writer { value: p }; }
11 +
fn unwrap 'r (w: Writer 'r) -> &'r mut u32 {
12 +
    let case Writer { value } = w else panic;
13 +
    return value;
14 +
}
15 +
fn project 'r (p: &'r u32) -> &'r u32 { return &*p; }
16 +
fn read 'r (r: Reader 'r) -> &'r u32 { return r.value; }
17 +
fn view 'r (v: View 'r) -> u32 {
18 +
    match v {
19 +
        case View::Item { value } => return *value,
20 +
        case View::Empty => return 0,
21 +
    }
22 +
}
23 +
fn fail 'r (p: &'r u32, other: bool) throws (Error 'r, Other) {
24 +
    if other {
25 +
        throw Other::Failed;
26 +
    }
27 +
    throw Error 'r { value: p };
28 +
}
29 +
fn catchValue 'r (p: &'r u32, other: bool) -> u32 {
30 +
    try fail(p, other) catch e as Error 'r {
31 +
        return *e.value;
32 +
    } catch e as Other {
33 +
        return 2;
34 +
    };
35 +
    return 0;
36 +
}
37 +
38 +
fn store 'long 'short (dst: &'short mut ?&'long u32, p: &'long u32) where 'long: 'short {
39 +
    set *dst = p;
40 +
}
41 +
fn fill 'long 'short (dst: &'short mut [&'long u32], p: &'long u32) where 'long: 'short {
42 +
    set dst[..] = p;
43 +
}
44 +
45 +
@default fn main() -> u32 {
46 +
    let mut value: u32 = 40;
47 +
    let p: 'write = &mut value in {
48 +
        let owner = writer(p);
49 +
        let q = unwrap(owner);
50 +
        set *q += 2;
51 +
    }
52 +
    let p: 'freeze = &mut value in {
53 +
        let q = project(p);
54 +
        assert *q == 42;
55 +
    }
56 +
    let p: 'read = &value in {
57 +
        let mut slot: ?&'read u32 = nil;
58 +
        let dst: 'slot = &mut slot in { store(dst, p); }
59 +
        let saved = slot else panic;
60 +
        assert *saved == 42;
61 +
        let mut pointers: [&'read u32; 2] = [p, p];
62 +
        let dst: 'items = &mut pointers[..] in { fill(dst, p); }
63 +
        assert *pointers[1] == 42;
64 +
        let r = reader(project(p));
65 +
        let values: [Reader 'read; 2] = [r, r];
66 +
        let some: ?Reader 'read = values[0];
67 +
        let got = some else panic;
68 +
        assert *read(got) == 42;
69 +
        let v: View 'read = View::Item { value: p };
70 +
        assert view(v) == 42;
71 +
        assert catchValue(p, false) == 42;
72 +
        assert catchValue(p, true) == 2;
73 +
    }
74 +
    return value;
75 +
}
test/tests/regions.storage.ril added +228 -0
1 +
fn w64 $reader(w64 %0) {
2 +
  @entry0
3 +
    reserve %1 8 8;
4 +
    store w64 %0 %1 0;
5 +
    load w64 %2 %1 0;
6 +
    ret %2;
7 +
}
8 +
9 +
fn w64 $writer(w64 %0) {
10 +
  @entry0
11 +
    reserve %1 8 8;
12 +
    store w64 %0 %1 0;
13 +
    load w64 %2 %1 0;
14 +
    ret %2;
15 +
}
16 +
17 +
fn w64 $unwrap(w64 %0) {
18 +
  @entry0
19 +
    reserve %1 8 8;
20 +
    blit %1 %0 8;
21 +
    jmp @success1;
22 +
  @success1
23 +
    load w64 %2 %1 0;
24 +
    jmp @merge3;
25 +
  @else2
26 +
    unreachable;
27 +
  @merge3
28 +
    ret %2;
29 +
}
30 +
31 +
fn w64 $project(w64 %0) {
32 +
  @entry0
33 +
    ret %0;
34 +
}
35 +
36 +
fn w64 $read(w64 %0) {
37 +
  @entry0
38 +
    load w64 %1 %0 0;
39 +
    ret %1;
40 +
}
41 +
42 +
fn w32 $view(w64 %0) {
43 +
  @entry0
44 +
    reserve %1 16 8;
45 +
    blit %1 %0 16;
46 +
    jmp @arm1;
47 +
  @arm1
48 +
    load w8 %2 %1 0;
49 +
    br.eq w8 %2 0 @case2 @arm3;
50 +
  @case2
51 +
    add w64 %3 %1 8;
52 +
    load w64 %4 %3 0;
53 +
    load w32 %5 %4 0;
54 +
    ret %5;
55 +
  @arm3
56 +
    jmp @case4;
57 +
  @case4
58 +
    ret 0;
59 +
}
60 +
61 +
fn w64 $fail(w64 %0, w64 %1, w8 %2) {
62 +
  @entry0
63 +
    br.ne w32 %2 0 @then1 @merge2;
64 +
  @then1
65 +
    reserve %3 16 8;
66 +
    store w64 1 %3 0;
67 +
    store w8 0 %3 8;
68 +
    blit %0 %3 16;
69 +
    ret %0;
70 +
  @merge2
71 +
    reserve %4 8 8;
72 +
    store w64 %1 %4 0;
73 +
    reserve %5 16 8;
74 +
    store w64 2 %5 0;
75 +
    add w64 %6 %5 8;
76 +
    blit %6 %4 8;
77 +
    blit %0 %5 16;
78 +
    ret %0;
79 +
}
80 +
81 +
fn w32 $catchValue(w64 %0, w8 %1) {
82 +
  @entry0
83 +
    reserve %2 16 8;
84 +
    call w64 %3 $fail(%2, %0, %1);
85 +
    load w64 %4 %3 0;
86 +
    br.ne w32 %4 0 @err2 @ok1;
87 +
  @ok1
88 +
    jmp @merge3;
89 +
  @err2
90 +
    switch %4 (2 @catch4) (1 @catch5) @unreachable6;
91 +
  @merge3
92 +
    ret 0;
93 +
  @catch4
94 +
    add w64 %5 %3 8;
95 +
    load w64 %6 %5 0;
96 +
    load w32 %7 %6 0;
97 +
    ret %7;
98 +
  @catch5
99 +
    load w8 %8 %3 8;
100 +
    ret 2;
101 +
  @unreachable6
102 +
    unreachable;
103 +
}
104 +
105 +
fn w64 $store(w64 %0, w64 %1) {
106 +
  @entry0
107 +
    store w64 %1 %0 0;
108 +
    ret;
109 +
}
110 +
111 +
fn w64 $fill(w64 %0, w64 %1) {
112 +
  @entry0
113 +
    load w64 %2 %0 0;
114 +
    load w32 %3 %0 8;
115 +
    jmp @fill1(0);
116 +
  @fill1(w32 %4)
117 +
    br.ult w32 %4 %3 @fill2 @fill3;
118 +
  @fill2
119 +
    mul w64 %5 %4 8;
120 +
    add w64 %6 %2 %5;
121 +
    store w64 %1 %6 0;
122 +
    add w32 %7 %4 1;
123 +
    jmp @fill1(%7);
124 +
  @fill3
125 +
    ret;
126 +
}
127 +
128 +
fn w32 $main() {
129 +
  @entry0
130 +
    reserve %0 4 4;
131 +
    store w32 40 %0 0;
132 +
    call w64 %1 $writer(%0);
133 +
    reserve %2 8 8;
134 +
    store w64 %1 %2 0;
135 +
    call w64 %3 $unwrap(%2);
136 +
    load w32 %4 %3 0;
137 +
    add w32 %5 %4 2;
138 +
    store w32 %5 %3 0;
139 +
    call w64 %6 $project(%0);
140 +
    load w32 %7 %6 0;
141 +
    br.eq w32 %7 42 @assert.ok2 @assert.fail1;
142 +
  @assert.fail1
143 +
    unreachable;
144 +
  @assert.ok2
145 +
    reserve %8 8 8;
146 +
    store w64 0 %8 0;
147 +
    call w64 $store(%8, %0);
148 +
    load w64 %9 %8 0;
149 +
    br.ne w32 %9 0 @success3 @else4;
150 +
  @success3
151 +
    jmp @merge5;
152 +
  @else4
153 +
    unreachable;
154 +
  @merge5
155 +
    load w32 %10 %9 0;
156 +
    br.eq w32 %10 42 @assert.ok7 @assert.fail6;
157 +
  @assert.fail6
158 +
    unreachable;
159 +
  @assert.ok7
160 +
    reserve %11 16 8;
161 +
    store w64 %0 %11 0;
162 +
    store w64 %0 %11 8;
163 +
    reserve %12 16 8;
164 +
    store w64 %11 %12 0;
165 +
    store w32 2 %12 8;
166 +
    store w32 2 %12 12;
167 +
    reserve %13 16 8;
168 +
    blit %13 %12 16;
169 +
    call w64 $fill(%13, %0);
170 +
    mul w64 %14 1 8;
171 +
    add w64 %15 %11 %14;
172 +
    load w64 %16 %15 0;
173 +
    load w32 %17 %16 0;
174 +
    br.eq w32 %17 42 @assert.ok9 @assert.fail8;
175 +
  @assert.fail8
176 +
    unreachable;
177 +
  @assert.ok9
178 +
    call w64 %18 $project(%0);
179 +
    call w64 %19 $reader(%18);
180 +
    reserve %20 8 8;
181 +
    store w64 %19 %20 0;
182 +
    reserve %21 16 8;
183 +
    blit %21 %20 8;
184 +
    add w64 %22 %21 8;
185 +
    blit %22 %20 8;
186 +
    reserve %23 16 8;
187 +
    store w8 1 %23 0;
188 +
    add w64 %24 %23 8;
189 +
    blit %24 %21 8;
190 +
    reserve %25 16 8;
191 +
    blit %25 %23 16;
192 +
    reserve %26 16 8;
193 +
    blit %26 %25 16;
194 +
    load w8 %27 %26 0;
195 +
    br.ne w32 %27 0 @success10 @else11;
196 +
  @success10
197 +
    add w64 %28 %26 8;
198 +
    jmp @merge12;
199 +
  @else11
200 +
    unreachable;
201 +
  @merge12
202 +
    call w64 %29 $read(%28);
203 +
    load w32 %30 %29 0;
204 +
    br.eq w32 %30 42 @assert.ok14 @assert.fail13;
205 +
  @assert.fail13
206 +
    unreachable;
207 +
  @assert.ok14
208 +
    reserve %31 16 8;
209 +
    store w8 0 %31 0;
210 +
    store w64 %0 %31 8;
211 +
    call w32 %32 $view(%31);
212 +
    br.eq w32 %32 42 @assert.ok16 @assert.fail15;
213 +
  @assert.fail15
214 +
    unreachable;
215 +
  @assert.ok16
216 +
    call w32 %33 $catchValue(%0, 0);
217 +
    br.eq w32 %33 42 @assert.ok18 @assert.fail17;
218 +
  @assert.fail17
219 +
    unreachable;
220 +
  @assert.ok18
221 +
    call w32 %34 $catchValue(%0, 1);
222 +
    br.eq w32 %34 2 @assert.ok20 @assert.fail19;
223 +
  @assert.fail19
224 +
    unreachable;
225 +
  @assert.ok20
226 +
    load w32 %35 %0 0;
227 +
    ret %35;
228 +
}
test/tests/static.local.names.rad added +25 -0
1 +
//! returns: 42
2 +
3 +
/// Increment the first function's persistent counter.
4 +
fn left() -> i32 {
5 +
    static VALUE: i32 = 9;
6 +
    constant STEP: i32 = 1;
7 +
    set VALUE += STEP;
8 +
    return VALUE;
9 +
}
10 +
11 +
/// Increment the second function's persistent counter.
12 +
fn right() -> i32 {
13 +
    static VALUE: i32 = 30;
14 +
    set VALUE += 1;
15 +
    return VALUE;
16 +
}
17 +
18 +
@default fn main() -> i32 {
19 +
    assert left() == 10;
20 +
    let first = left();
21 +
    let second = right();
22 +
    assert first == 11;
23 +
    assert second == 31;
24 +
    return first + second;
25 +
}
test/tests/static.local.names.ril added +56 -0
1 +
data mut $left$nominal$VALUE align 4 {
2 +
    w32 9;
3 +
}
4 +
5 +
data $left$nominal$STEP align 4 {
6 +
    w32 1;
7 +
}
8 +
9 +
data mut $right$nominal$VALUE align 4 {
10 +
    w32 30;
11 +
}
12 +
13 +
fn w32 $left() {
14 +
  @entry0
15 +
    copy %0 $left$nominal$VALUE;
16 +
    sload w32 %1 %0 0;
17 +
    add w32 %2 %1 1;
18 +
    copy %3 $left$nominal$VALUE;
19 +
    store w32 %2 %3 0;
20 +
    copy %4 $left$nominal$VALUE;
21 +
    sload w32 %5 %4 0;
22 +
    ret %5;
23 +
}
24 +
25 +
fn w32 $right() {
26 +
  @entry0
27 +
    copy %0 $right$nominal$VALUE;
28 +
    sload w32 %1 %0 0;
29 +
    add w32 %2 %1 1;
30 +
    copy %3 $right$nominal$VALUE;
31 +
    store w32 %2 %3 0;
32 +
    copy %4 $right$nominal$VALUE;
33 +
    sload w32 %5 %4 0;
34 +
    ret %5;
35 +
}
36 +
37 +
fn w32 $main() {
38 +
  @entry0
39 +
    call w32 %0 $left();
40 +
    br.eq w32 %0 10 @assert.ok2 @assert.fail1;
41 +
  @assert.fail1
42 +
    unreachable;
43 +
  @assert.ok2
44 +
    call w32 %1 $left();
45 +
    call w32 %2 $right();
46 +
    br.eq w32 %1 11 @assert.ok4 @assert.fail3;
47 +
  @assert.fail3
48 +
    unreachable;
49 +
  @assert.ok4
50 +
    br.eq w32 %2 31 @assert.ok6 @assert.fail5;
51 +
  @assert.fail5
52 +
    unreachable;
53 +
  @assert.ok6
54 +
    add w32 %3 %1 %2;
55 +
    ret %3;
56 +
}
test/tests/static.optional.nil.rad added +24 -0
1 +
//! returns: 0
2 +
//! Static nil values occupy their complete scalar, pointer, and aggregate layouts.
3 +
4 +
/// Payload with alignment and padding requirements.
5 +
record Payload: Copy { base: u64, count: u32 }
6 +
/// Adjacent fields must remain intact around a nil aggregate.
7 +
record Container: Copy { first: u64, item: ?Payload, last: u64 }
8 +
9 +
static VALUE: ?Payload = nil;
10 +
static NUMBER: ?u64 = nil;
11 +
static POINTER: ?*u64 = nil;
12 +
static ITEMS: [?Payload; 2] = [nil; 2];
13 +
static BOX: Container = Container { first: 0x1122334455667788, item: nil, last: 0x8877665544332211 };
14 +
15 +
/// Check complete nil layouts and subsequent mutable initialization.
16 +
@default fn main() -> i32 {
17 +
    assert VALUE == nil and NUMBER == nil and POINTER == nil;
18 +
    assert ITEMS[0] == nil and ITEMS[1] == nil;
19 +
    assert BOX.item == nil and BOX.first == 0x1122334455667788 and BOX.last == 0x8877665544332211;
20 +
    set VALUE = Payload { base: 42, count: 7 };
21 +
    let value = VALUE else panic "missing initialized payload";
22 +
    assert value.base == 42 and value.count == 7;
23 +
    return 0;
24 +
}