///|
/// Source and liveness information for one operation, including any checks
/// emitted before its selected instruction.
#valtype
pub struct DirectOperationSource {
priv source : @native.SourceLocation?
priv stack_map : @native.StackMapMetadata?
priv roots : Array[Value]
priv semantics : @native.OperationSemantics
}
///|
pub fn DirectOperationSource::new(
source : @native.SourceLocation?,
stack_map : @native.StackMapMetadata?,
roots : Array[Value],
semantics : @native.OperationSemantics,
) -> DirectOperationSource {
{ source, stack_map, roots, semantics, }
}
///|
pub fn DirectOperationSource::metadata(
self : DirectOperationSource,
trap? : @native.TrapReason,
) -> InstructionMetadata {
direct_source_metadata(
self.source,
self.stack_map,
self.roots,
self.semantics,
trap?,
)
}
///|
pub fn DirectOperationSource::selected_metadata(
self : DirectOperationSource,
operation : @lowering.Operation,
) -> InstructionMetadata {
let trap = match operation {
Load(spec) => spec.trap
Store(spec) => spec.trap
VectorLoad(spec) => spec.trap
VectorStoreLane(spec) => spec.trap
AtomicLoad(spec)
| AtomicStore(spec)
| AtomicRmw(spec, _)
| AtomicCompareExchange(spec) => spec.trap
_ => None
}
self.metadata(trap?)
}
///|
fn float_to_int_bounds(
source : @native.FloatType,
result : @native.IntegerType,
signedness : @native.Signedness,
) -> (UInt64, UInt64, Bool) {
match (source, result, signedness) {
(F32, I32, Signed) => (0xCF000000UL, 0x4F000000UL, false)
(F32, I32, Unsigned) => (0xBF800000UL, 0x4F800000UL, true)
(F32, I64, Signed) => (0xDF000000UL, 0x5F000000UL, false)
(F32, I64, Unsigned) => (0xBF800000UL, 0x5F800000UL, true)
(F64, I32, Signed) => (0xC1E0000000200000UL, 0x41E0000000000000UL, true)
(F64, I32, Unsigned) => (0xBFF0000000000000UL, 0x41F0000000000000UL, true)
(F64, I64, Signed) => (0xC3E0000000000000UL, 0x43E0000000000000UL, false)
(F64, I64, Unsigned) => (0xBFF0000000000000UL, 0x43F0000000000000UL, true)
}
}
///|
/// Preserve NaN and range trap order before a trapping conversion. Targets
/// supply the concrete trap pseudos, which have no implicit clobbers.
pub fn[Inst] CheckedBuilder::append_float_to_int_checks(
self : CheckedBuilder[Inst],
block : Block,
operand : Value,
source : @native.FloatType,
result : @native.IntegerType,
signedness : @native.Signedness,
site : DirectOperationSource,
float_constant : (@native.ValueType, UInt64) -> Inst,
trap_unordered : (@native.ValueType) -> Inst,
trap_minimum : (@native.ValueType, Bool) -> Inst,
trap_maximum : (@native.ValueType) -> Inst,
) -> Unit raise VCodeBuildError {
let ty : @native.ValueType = match source {
F32 => F32
F64 => F64
}
self.append_body(
block,
trap_unordered(ty),
[Input::any(operand)],
[],
[],
site.metadata(trap=InvalidConversionToInteger),
)
|> ignore
let (minimum, maximum, inclusive_minimum) = float_to_int_bounds(
source, result, signedness,
)
for
bound_check in [
(minimum, trap_minimum(ty, inclusive_minimum)),
(maximum, trap_maximum(ty)),
] {
let (bound, trap) = bound_check
let (_, values) = self.append_body(
block,
float_constant(ty, bound),
[],
[Output::any(ty)],
[],
InstructionMetadata::empty(),
)
self.append_body(
block,
trap,
[Input::any(operand), Input::any(values[0])],
[],
[],
site.metadata(trap=IntegerOverflow),
)
|> ignore
}
}
///|
/// Atomic pseudos address memory at offset zero. Materialize a nonzero static
/// offset before the selected atomic instruction and leave trap metadata there.
pub fn[Inst] CheckedBuilder::materialize_atomic_address(
self : CheckedBuilder[Inst],
block : Block,
operation : @lowering.Operation,
operands : Array[Value],
load_offset : (UInt64) -> Inst,
add_address : Inst,
) -> Array[Value] raise VCodeBuildError {
let offset = match operation {
AtomicLoad(spec)
| AtomicStore(spec)
| AtomicRmw(spec, _)
| AtomicCompareExchange(spec) => spec.offset
_ => 0UL
}
if offset == 0UL {
return operands
}
let (_, offset_values) = self.append_body(
block,
load_offset(offset),
[],
[Output::any(I64)],
[],
InstructionMetadata::empty(),
)
let (_, addresses) = self.append_body(
block,
add_address,
[Input::any(operands[0]), Input::any(offset_values[0])],
[Output::any(Ptr64)],
[],
InstructionMetadata::empty(),
)
let values = operands.copy()
values[0] = addresses[0]
values
}