compiler: Use scoped allocator for checked function construction

ad67060625275231a9e473c297296a32e27ff8c060f71cba88c6ebc0c9034775
Alexis Sellier committed ago 1 parent 3122b8f7
lib/std/lang/lower.rad +27 -25
734 734
record FnLowerer: 'arena + 'phase + 'function where 'arena: 'phase, 'phase: 'function {
735 735
    /// Reference to the module-level lowerer.
736 736
    low: &'function mut Lowerer 'arena 'phase,
737 737
    /// Arena for allocations owned by this function.
738 738
    arena: &'function mut alloc::Arena,
739 +
    /// Allocator backed by the function arena for the full lowering scope.
740 +
    allocator: alloc::Allocator,
739 741
    /// Type signature of the function being lowered.
740 742
    fnType: *resolver::FnType,
741 743
    /// Number of SSA variable slots required for each block.
742 744
    localCount: u32,
743 745
    /// Function name, used as prefix for generated data symbols.
1028 1030
    self: &'function mut Lowerer 'arena 'phase,
1029 1031
    sourceOffset: u32,
1030 1032
    fnType: *resolver::FnType,
1031 1033
    qualName: *[u8],
1032 1034
    functionArena: &'function mut alloc::Arena,
1033 -
    variables: &'function mut [VarData]
1035 +
    variables: &'function mut [VarData],
1036 +
    allocator: alloc::Allocator
1034 1037
) -> FnLowerer 'arena 'phase 'function where 'arena: 'phase, 'phase: 'function {
1035 1038
    let localCount = variables.len;
1036 1039
    let mut fnLow = FnLowerer 'arena 'phase 'function {
1037 1040
        low: self,
1038 1041
        arena: functionArena,
1042 +
        allocator,
1039 1043
        fnType,
1040 1044
        localCount,
1041 1045
        fnName: qualName,
1042 1046
        vars: Variables 'function { items: variables, len: 0 },
1043 1047
        params: [FnParamBinding { var: Var(0), reg: il::Reg { n: 0 } }; resolver::MAX_FN_PARAMS],
1114 1118
1115 1119
    // Register function symbol for cross-package call resolution.
1116 1120
    if let sym = resolver::symbolFor(self.resolver, node) {
1117 1121
        registerSymbolName(&mut self.symbolNames, sym, qualName, alloc::arenaAllocator(self.arena));
1118 1122
    }
1119 -
    let variableSlots = variableStorage(data.localCount, alloc::arenaAllocator(functionArena));
1123 +
    let allocator = alloc::arenaAllocator(functionArena);
1124 +
    let variableSlots = variableStorage(data.localCount, allocator);
1120 1125
    let parent: 'function = &mut *self, arena = &mut *functionArena, variables = &mut variableSlots[..] where 'phase: 'function in {
1121 -
        let mut fnLow = fnLowerer(parent, node.span.offset, fnType, qualName, arena, variables);
1126 +
        let mut fnLow = fnLowerer(parent, node.span.offset, fnType, qualName, arena, variables, allocator);
1122 1127
1123 1128
        // If the function returns an aggregate or is throwing, prepend a hidden
1124 1129
        // return parameter. The caller allocates the buffer and passes it
1125 1130
        // as the first argument; the callee writes the return value into it.
1126 1131
        if requiresReturnParam(fnType) and not isExtern {
1278 1283
        throw LowerError::ExpectedFunction;
1279 1284
    };
1280 1285
    let sym = resolver::symbolFor(self.resolver, node) else throw LowerError::MissingSymbol(node);
1281 1286
    registerSymbolName(&mut self.symbolNames, sym, qualName, alloc::arenaAllocator(self.arena));
1282 1287
1283 -
    let variableSlots = variableStorage(data.localCount, alloc::arenaAllocator(functionArena));
1288 +
    let allocator = alloc::arenaAllocator(functionArena);
1289 +
    let variableSlots = variableStorage(data.localCount, allocator);
1284 1290
    let parent: 'function = &mut *self, arena = &mut *functionArena, variables = &mut variableSlots[..] where 'phase: 'function in {
1285 -
        let mut fnLow = fnLowerer(parent, node.span.offset, fnType, qualName, arena, variables);
1291 +
        let mut fnLow = fnLowerer(parent, node.span.offset, fnType, qualName, arena, variables, allocator);
1286 1292
        if requiresReturnParam(fnType) {
1287 1293
            set fnLow.returnReg = nextReg(&mut fnLow);
1288 1294
        }
1289 1295
        let lowParams = try lowerParams(&mut fnLow, *fnType, sig.params, receiverName);
1290 1296
        let func = try! alloc::alloc(&mut *fnLow.arena, @sizeOf(il::Fn), @alignOf(il::Fn)) as *mut il::Fn;
1351 1357
    }
1352 1358
    return buf;
1353 1359
}
1354 1360
1355 1361
/// Generate a unique label by appending the global counter to the base.
1356 -
unsafe fn nextLabel 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: *[u8]) -> *[u8] throws (LowerError) where 'arena: 'phase, 'phase: 'function {
1362 +
fn nextLabel 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, base: *[u8]) -> *[u8] throws (LowerError) where 'arena: 'phase, 'phase: 'function {
1357 1363
    let idx = self.labelCounter;
1358 1364
    set self.labelCounter += 1;
1359 1365
1360 -
    return labelWithSuffix(base, idx, alloc::arenaAllocator(self.arena));
1366 +
    return labelWithSuffix(base, idx, self.allocator);
1361 1367
}
1362 1368
1363 1369
///////////////////////////////
1364 1370
// Data Section Construction //
1365 1371
///////////////////////////////
2161 2167
/// Create a new basic block with the given label base.
2162 2168
///
2163 2169
/// The block is initially unsealed (predecessors may be added later) and empty.
2164 2170
/// Returns a [`BlockId`] that can be used for jumps and branches. The block must
2165 2171
/// be switched to via [`switchToBlock`] before instructions can be emitted.
2166 -
unsafe fn createBlock 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, labelBase: *[u8]) -> BlockId throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2172 +
fn createBlock 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, labelBase: *[u8]) -> BlockId throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2167 2173
    let label = try nextLabel(self, labelBase);
2168 2174
    let varCount = self.localCount;
2169 -
    let allocator = alloc::arenaAllocator(self.arena);
2175 +
    let allocator = self.allocator;
2170 2176
    let depth = self.loopDepth;
2171 2177
    return appendBlock(&mut self.blockData, label, varCount, depth, allocator);
2172 2178
}
2173 2179
2174 2180
/// Append a complete unsealed block with initialized variable slots.
2198 2204
2199 2205
    return id;
2200 2206
}
2201 2207
2202 2208
/// Create a new block with a single parameter.
2203 -
unsafe fn createBlockWithParam 'arena 'phase 'function (
2209 +
fn createBlockWithParam 'arena 'phase 'function (
2204 2210
    self: &mut FnLowerer 'arena 'phase 'function,
2205 2211
    labelBase: *[u8],
2206 2212
    param: il::Param
2207 2213
) -> BlockId throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2208 2214
    let block = try createBlock(self, labelBase);
2209 -
    let allocator = alloc::arenaAllocator(self.arena);
2215 +
    let allocator = self.allocator;
2210 2216
    self.blockData[*block].params.append(param, allocator);
2211 2217
2212 2218
    return block;
2213 2219
}
2214 2220
2266 2272
//////////////////////////
2267 2273
// Instruction Emission //
2268 2274
//////////////////////////
2269 2275
2270 2276
/// Emit an instruction to the current block.
2271 -
unsafe fn emit 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, instr: il::Instr) where 'arena: 'phase, 'phase: 'function {
2272 -
    let allocator = alloc::arenaAllocator(self.arena);
2277 +
fn emit 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, instr: il::Instr) where 'arena: 'phase, 'phase: 'function {
2278 +
    let allocator = self.allocator;
2273 2279
    recordInstruction(self, &instr, allocator);
2274 2280
}
2275 2281
2276 2282
/// Append an instruction and its enabled source location to the current block.
2277 2283
fn recordInstruction 'arena 'phase 'function (
2772 2778
// Control Flow Edge Management //
2773 2779
//////////////////////////////////
2774 2780
2775 2781
/// Add a predecessor edge from `pred` to `target`.
2776 2782
/// Must be called before the target block is sealed. Duplicates are ignored.
2777 -
unsafe fn addPredecessor 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId, pred: BlockId) where 'arena: 'phase, 'phase: 'function {
2778 -
    let allocator = alloc::arenaAllocator(self.arena);
2783 +
fn addPredecessor 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, target: BlockId, pred: BlockId) where 'arena: 'phase, 'phase: 'function {
2784 +
    let allocator = self.allocator;
2779 2785
    insertPredecessor(&mut self.blockData[..], target, pred, allocator);
2780 2786
}
2781 2787
2782 2788
/// Insert one distinct predecessor into an unsealed block's owned list.
2783 2789
fn insertPredecessor(blocks: &mut [BlockData], target: BlockId, pred: BlockId, allocator: alloc::Allocator) {
2840 2846
    }
2841 2847
    return self.loopStack[self.loopDepth - 1];
2842 2848
}
2843 2849
2844 2850
/// Get or lazily create the continue target block for the current loop.
2845 -
unsafe fn getOrCreateContinueBlock 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) -> BlockId throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2851 +
fn getOrCreateContinueBlock 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) -> BlockId throws (LowerError) where 'arena: 'phase, 'phase: 'function {
2846 2852
    let ctx = currentLoop(self) else {
2847 2853
        throw LowerError::OutsideOfLoop;
2848 2854
    };
2849 2855
    if let block = ctx.continueTarget {
2850 2856
        return block;
3018 3024
            let val = try useVarInBlock(self, pred, v);
3019 3025
            set self.blockData[*block].vars[*v] = val; // Cache.
3020 3026
            return val;
3021 3027
        }
3022 3028
        case VarSource::Merge => {
3023 -
            unsafe {
3024 -
                let allocator = alloc::arenaAllocator(self.arena);
3025 -
                return try createBlockParam(self, block, v, allocator);
3026 -
            }
3029 +
            let allocator = self.allocator;
3030 +
            return try createBlockParam(self, block, v, allocator);
3027 3031
        },
3028 3032
        case VarSource::Invalid => throw LowerError::InvalidUse,
3029 3033
    }
3030 3034
}
3031 3035
3182 3186
        let pred = BlockId(self.blockData[*block].preds[index]);
3183 3187
        // This may recursively trigger more block arg resolution if the
3184 3188
        // predecessor also needs to look up the variable from its predecessors.
3185 3189
        let val = try useVarInBlock(self, pred, v);
3186 3190
        assert val <> il::Val::Undef, "createBlockParam: predecessor provides undef value for block parameter";
3187 -
        unsafe {
3188 -
            patchTerminatorArg(self, pred, *block, paramIdx, val);
3189 -
        }
3191 +
        patchTerminatorArg(self, pred, *block, paramIdx, val);
3190 3192
    }
3191 3193
}
3192 3194
3193 3195
/// Check if a block parameter is trivial, i.e. all predecessors provide
3194 3196
/// the same value. Returns the trivial value if so.
3224 3226
    return sameVal;
3225 3227
}
3226 3228
3227 3229
/// Patch a single terminator argument for a specific edge. This is used during
3228 3230
/// SSA construction to pass variable values along control flow edges.
3229 -
unsafe fn patchTerminatorArg 'arena 'phase 'function (
3231 +
fn patchTerminatorArg 'arena 'phase 'function (
3230 3232
    self: &mut FnLowerer 'arena 'phase 'function,
3231 3233
    from: BlockId,         // The predecessor block containing the terminator to patch.
3232 3234
    target: u32,           // The index of the target block we're passing the value to.
3233 3235
    paramIdx: u32,         // The index of the block parameter to set.
3234 3236
    val: il::Val           // The value to pass as the argument.
3235 3237
) where 'arena: 'phase, 'phase: 'function {
3236 -
    let allocator = alloc::arenaAllocator(self.arena);
3238 +
    let allocator = self.allocator;
3237 3239
    // Get mutable block data by block id.
3238 3240
    let data = &mut self.blockData[*from];
3239 3241
    let ix = data.instrs.len - 1; // The terminator is always the last instruction.
3240 3242
    patchEdgeArgs(&mut data.instrs[ix], target, paramIdx, val, allocator);
3241 3243
}