|
| 1 | +# Rust Intrinsic Functions in K |
| 2 | + |
| 3 | +```k |
| 4 | +// This looks like a circular import but only module KMIR in kmir.md imports KMIR-INTRINSICS |
| 5 | +requires "kmir.md" |
| 6 | +
|
| 7 | +module KMIR-INTRINSICS |
| 8 | + imports KMIR-CONTROL-FLOW |
| 9 | +``` |
| 10 | + |
| 11 | +### Intrinsic Functions |
| 12 | + |
| 13 | +Intrinsic functions are built-in functions provided by the compiler that don't have regular MIR bodies. |
| 14 | +They are handled specially in the execution semantics through the `#execIntrinsic` mechanism. |
| 15 | +When an intrinsic function is called, the execution bypasses the normal function call setup and directly |
| 16 | +executes the intrinsic-specific logic. |
| 17 | + |
| 18 | +#### Black Box (`std::hint::black_box`) |
| 19 | + |
| 20 | +The `black_box` intrinsic serves as an optimization barrier, preventing the compiler from making assumptions |
| 21 | +about the value passed through it. In the semantics, it acts as an identity function that simply passes |
| 22 | +its argument to the destination without modification. |
| 23 | + |
| 24 | +```k |
| 25 | + // Black box intrinsic implementation - identity function |
| 26 | + rule <k> #execIntrinsic(IntrinsicFunction(symbol("black_box")), ARG:Operand .Operands, DEST) |
| 27 | + => #setLocalValue(DEST, ARG) |
| 28 | + ... </k> |
| 29 | +``` |
| 30 | + |
| 31 | +#### Cold Path (`std::hint::cold_path`) |
| 32 | + |
| 33 | +The `cold_path` intrinsic is a compiler hint indicating that the current execution path is unlikely to be taken. |
| 34 | +It provides metadata for the optimiser and code generator to improve layout and branch predicition but is |
| 35 | +a NO OP for program semantics. `std::intrinsics::likely` and `std::intrinsics::unlikely` are |
| 36 | +"normal" `MonoItemFn`s that call the `cold_path` intrinsic. |
| 37 | + |
| 38 | +```k |
| 39 | + rule <k> #execIntrinsic(IntrinsicFunction(symbol("cold_path")), .Operands, _DEST) => .K ... </k> |
| 40 | +``` |
| 41 | + |
| 42 | +#### Prefetch (`std::intrinsics::prefetch_*`) |
| 43 | + |
| 44 | +The `prefetch_read_data`, `prefetch_write_data`, `prefetch_read_instruction`, and `prefetch_write_instruction` |
| 45 | +intrinsics in Rust are performance hints that request the CPU to load or prepare a memory address in cache |
| 46 | +before it's used. They have no effect on program semantics, and are implemented as a NO OP in this semantics. |
| 47 | + |
| 48 | +```k |
| 49 | + rule <k> #execIntrinsic(IntrinsicFunction(symbol("prefetch_read_data")), _ARG1:Operand _ARG2:Operand .Operands, _DEST) => .K ... </k> |
| 50 | + rule <k> #execIntrinsic(IntrinsicFunction(symbol("prefetch_write_data")), _ARG1:Operand _ARG2:Operand .Operands, _DEST) => .K ... </k> |
| 51 | +
|
| 52 | + rule <k> #execIntrinsic(IntrinsicFunction(symbol("prefetch_read_instruction")), _ARG1:Operand _ARG2:Operand .Operands, _DEST) => .K ... </k> |
| 53 | + rule <k> #execIntrinsic(IntrinsicFunction(symbol("prefetch_write_instruction")), _ARG1:Operand _ARG2:Operand .Operands, _DEST) => .K ... </k> |
| 54 | +``` |
| 55 | + |
| 56 | +#### Raw Eq (`std::intrinsics::raw_eq`) |
| 57 | + |
| 58 | +The `raw_eq` intrinsic performs byte-by-byte equality comparison of the memory contents pointed to by two references. |
| 59 | +It returns a boolean value indicating whether the referenced values are equal. The implementation dereferences the |
| 60 | +provided references to access the underlying values, then compares them using K's built-in equality operator. |
| 61 | + |
| 62 | +**Type Safety:** |
| 63 | +The implementation requires operands to have identical types (`TY1 ==K TY2`) before performing the comparison. |
| 64 | +Execution gets stuck (no matching rule) when operands have different types or unknown type information. |
| 65 | + |
| 66 | +```k |
| 67 | + // Raw eq: dereference operands, extract types, and delegate to typed comparison |
| 68 | + rule <k> #execIntrinsic(IntrinsicFunction(symbol("raw_eq")), ARG1:Operand ARG2:Operand .Operands, PLACE) |
| 69 | + => #execRawEqTyped(PLACE, #withDeref(ARG1), #extractOperandType(#withDeref(ARG1), LOCALS), |
| 70 | + #withDeref(ARG2), #extractOperandType(#withDeref(ARG2), LOCALS)) |
| 71 | + ... </k> |
| 72 | + <locals> LOCALS </locals> |
| 73 | +
|
| 74 | + // Compare values only if types are identical |
| 75 | + syntax KItem ::= #execRawEqTyped(Place, Evaluation, MaybeTy, Evaluation, MaybeTy) [seqstrict(2,4)] |
| 76 | + rule <k> #execRawEqTyped(DEST, VAL1:Value, TY1:Ty, VAL2:Value, TY2:Ty) |
| 77 | + => #setLocalValue(DEST, BoolVal(VAL1 ==K VAL2)) |
| 78 | + ... </k> |
| 79 | + requires TY1 ==K TY2 |
| 80 | + [preserves-definedness] |
| 81 | +
|
| 82 | + // Add deref projection to operands |
| 83 | + syntax Operand ::= #withDeref(Operand) [function, total] |
| 84 | + rule #withDeref(operandCopy(place(LOCAL, PROJ))) |
| 85 | + => operandCopy(place(LOCAL, appendP(PROJ, projectionElemDeref .ProjectionElems))) |
| 86 | + rule #withDeref(operandMove(place(LOCAL, PROJ))) |
| 87 | + => operandCopy(place(LOCAL, appendP(PROJ, projectionElemDeref .ProjectionElems))) |
| 88 | + // must not overwrite the value, just the reference is moved! |
| 89 | + rule #withDeref(OP) => OP [owise] |
| 90 | +
|
| 91 | + // Extract type from operands (locals with projections, constants, fallback to unknown) |
| 92 | + syntax MaybeTy ::= #extractOperandType(Operand, List) [function, total] |
| 93 | + rule #extractOperandType(operandCopy(place(local(I), PROJS)), LOCALS) |
| 94 | + => getTyOf(tyOfLocal({LOCALS[I]}:>TypedLocal), PROJS) |
| 95 | + requires 0 <=Int I andBool I <Int size(LOCALS) andBool isTypedLocal(LOCALS[I]) |
| 96 | + [preserves-definedness] |
| 97 | + rule #extractOperandType(operandMove(place(local(I), PROJS)), LOCALS) |
| 98 | + => getTyOf(tyOfLocal({LOCALS[I]}:>TypedLocal), PROJS) |
| 99 | + requires 0 <=Int I andBool I <Int size(LOCALS) andBool isTypedLocal(LOCALS[I]) |
| 100 | + [preserves-definedness] |
| 101 | + rule #extractOperandType(operandConstant(constOperand(_, _, mirConst(_, TY, _))), _) => TY |
| 102 | + rule #extractOperandType(_, _) => TyUnknown [owise] |
| 103 | +``` |
| 104 | + |
| 105 | +```k |
| 106 | +endmodule |
| 107 | +``` |
0 commit comments