@unaligned_store and @unaligned_load

This commit is contained in:
Christoffer Lerno
2024-06-29 23:09:12 +02:00
parent d1e2ea7635
commit 09876cefde
9 changed files with 98 additions and 18 deletions

View File

@@ -8,6 +8,10 @@ import std::math;
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
macro bool @constant_is_power_of_2($x) @private
{
return $x != 0 && ($x & ($x - 1)) == 0;
}
/**
* Load a vector from memory according to a mask assuming default alignment.
@@ -37,7 +41,7 @@ macro masked_load(ptr, bool[<*>] mask, passthru)
* @require $assignable(&&passthru, $typeof(ptr)) : "Pointer and passthru must match"
* @require @typekind(passthru) == VECTOR : "Expected passthru to be a vector"
* @require passthru.len == mask.len : "Mask and passthru must have the same length"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*
* @return "A vector with the loaded values where the mask is true, passthru where the mask is false"
**/
@@ -80,7 +84,7 @@ macro gather(ptrvec, bool[<*>] mask, passthru)
* @require $assignable(&&passthru[0], $typeof(ptrvec[0])) : "Pointer and passthru must match"
* @require passthru.len == mask.len : "Mask and passthru must have the same length"
* @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*
* @return "A vector with the loaded values where the mask is true, passthru where the mask is false"
**/
@@ -115,7 +119,7 @@ macro masked_store(ptr, value, bool[<*>] mask)
* @require $assignable(&&value, $typeof(ptr)) : "Pointer and value must match"
* @require @typekind(value) == VECTOR : "Expected value to be a vector"
* @require value.len == mask.len : "Mask and value must have the same length"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*
**/
macro @masked_store_aligned(ptr, value, bool[<*>] mask, usz $alignment)
@@ -150,13 +154,35 @@ macro scatter(ptrvec, value, bool[<*>] mask)
* @require $assignable(&&value[0], $typeof(ptrvec[0])) : "Pointer and value must match"
* @require value.len == mask.len : "Mask and value must have the same length"
* @require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
* @require math::is_power_of_2($alignment) : "The alignment must be a power of two"
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
**/
macro @scatter_aligned(ptrvec, value, bool[<*>] mask, usz $alignment)
{
return $$scatter(ptrvec, value, mask, $alignment);
}
/**
* @param [in] x "the variable or dereferenced pointer to load."
* @param $alignment "the alignment to assume for the load"
* @return "returns the value of x"
*
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
**/
macro @unaligned_load(&x, usz $alignment) @builtin
{
return $$unaligned_load(x, $alignment);
}
/**
* @require $assignable(y, $typeof(*x)) : "The value doesn't match the variable"
*
* @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
**/
macro @unaligned_store(&x, y, usz $alignment) @builtin
{
return $$unaligned_store(x, ($typeof(*x))y, $alignment);
}
macro @volatile_load(&x) @builtin
{
return $$volatile_load(x);

View File

@@ -11,6 +11,7 @@
- Require `@export` functions to have `@export` types.
- Disallow leading/trailing/duplicate '_' in module names.
- Updated mangling.
- Added `$$unaligned_load` and `$$unaligned_store`.
### Fixes
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
@@ -29,6 +30,7 @@
- Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions.
- Added @str_hash, @str_upper, @str_lower, @str_find compile time macros.
- Remove "panic" text from unreachable() when safe mode is turned off.
- Added `@unaligned_store` and `@unaligned_load`.
## 0.6.0 Change list

View File

@@ -965,6 +965,8 @@ typedef enum
BUILTIN_SYSCLOCK,
BUILTIN_TRAP,
BUILTIN_TRUNC,
BUILTIN_UNALIGNED_LOAD,
BUILTIN_UNALIGNED_STORE,
BUILTIN_UNREACHABLE,
BUILTIN_VECCOMPLT,
BUILTIN_VECCOMPLE,

View File

@@ -161,6 +161,16 @@ INLINE void llvm_emit_atomic_store(GenContext *c, BEValue *result_value, Expr *e
}
}
INLINE void llvm_emit_unaligned_store(GenContext *c, BEValue *result_value, Expr *expr)
{
BEValue value;
llvm_emit_expr(c, &value, expr->call_expr.arguments[0]);
llvm_emit_expr(c, result_value, expr->call_expr.arguments[1]);
llvm_value_deref(c, &value);
value.alignment = expr->call_expr.arguments[2]->const_expr.ixx.i.low;
llvm_store(c, &value, result_value);
}
INLINE void llvm_emit_atomic_fetch(GenContext *c, BuiltinFunction func, BEValue *result_value, Expr *expr)
{
BEValue value;
@@ -232,6 +242,14 @@ INLINE void llvm_emit_atomic_load(GenContext *c, BEValue *result_value, Expr *ex
LLVMSetOrdering(result_value->value, llvm_atomic_ordering(expr->call_expr.arguments[2]->const_expr.ixx.i.low));
}
INLINE void llvm_emit_unaligned_load(GenContext *c, BEValue *result_value, Expr *expr)
{
llvm_emit_expr(c, result_value, expr->call_expr.arguments[0]);
llvm_value_deref(c, result_value);
result_value->alignment = expr->call_expr.arguments[1]->const_expr.ixx.i.low;
llvm_value_rvalue(c, result_value);
}
static inline LLVMValueRef llvm_syscall_asm(GenContext *c, LLVMTypeRef func_type, char *call)
{
return LLVMGetInlineAsm(func_type, call, strlen(call),
@@ -837,6 +855,12 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
case BUILTIN_ATOMIC_FETCH_EXCHANGE:
llvm_emit_atomic_fetch(c, func, result_value, expr);
return;
case BUILTIN_UNALIGNED_LOAD:
llvm_emit_unaligned_load(c, result_value, expr);
return;
case BUILTIN_UNALIGNED_STORE:
llvm_emit_unaligned_store(c, result_value, expr);
return;
case BUILTIN_ATOMIC_LOAD:
llvm_emit_atomic_load(c, result_value, expr);
return;

View File

@@ -825,6 +825,29 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
rtype = original->pointer;
break;
}
case BUILTIN_UNALIGNED_LOAD:
{
assert(arg_count == 2);
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_INTEGER}, 2)) return false;
Type *original = type_flatten(args[0]->type);
if (original == type_voidptr) RETURN_SEMA_ERROR(args[0], "Expected a typed pointer.");
if (!sema_check_alignment_expression(context, args[1])) return false;
rtype = original->pointer;
break;
}
case BUILTIN_UNALIGNED_STORE:
{
assert(arg_count == 3);
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_INTEGER }, 2)) return false;
Type *original = type_flatten(args[0]->type);
if (!sema_check_alignment_expression(context, args[2])) return false;
if (original != type_voidptr)
{
if (!cast_implicit(context, args[1], original->pointer)) return false;
}
rtype = args[1]->type;
break;
}
case BUILTIN_VOLATILE_LOAD:
{
assert(arg_count == 1);
@@ -1069,6 +1092,7 @@ static inline int builtin_expected_args(BuiltinFunction func)
case BUILTIN_VECCOMPEQ:
case BUILTIN_WASM_MEMORY_GROW:
case BUILTIN_ANY_MAKE:
case BUILTIN_UNALIGNED_LOAD:
return 2;
case BUILTIN_EXPECT_WITH_PROBABILITY:
case BUILTIN_FMA:
@@ -1080,6 +1104,7 @@ static inline int builtin_expected_args(BuiltinFunction func)
case BUILTIN_OVERFLOW_SUB:
case BUILTIN_PREFETCH:
case BUILTIN_ATOMIC_LOAD:
case BUILTIN_UNALIGNED_STORE:
case BUILTIN_SELECT:
return 3;
case BUILTIN_ATOMIC_STORE:

View File

@@ -272,6 +272,8 @@ void symtab_init(uint32_t capacity)
builtin_list[BUILTIN_VECCOMPEQ] = KW_DEF("veccompeq");
builtin_list[BUILTIN_VECCOMPNE] = KW_DEF("veccompne");
builtin_list[BUILTIN_UNREACHABLE] = KW_DEF("unreachable");
builtin_list[BUILTIN_UNALIGNED_LOAD] = KW_DEF("unaligned_load");
builtin_list[BUILTIN_UNALIGNED_STORE] = KW_DEF("unaligned_store");
builtin_list[BUILTIN_VOLATILE_LOAD] = KW_DEF("volatile_load");
builtin_list[BUILTIN_VOLATILE_STORE] = KW_DEF("volatile_store");
builtin_list[BUILTIN_WASM_MEMORY_GROW] = KW_DEF("wasm_memory_grow");

View File

@@ -257,11 +257,10 @@ class Issues:
if current_line >= len(lines):
self.set_failed()
print(file.filename + " did not contain: \"" + line + "\"")
print("");
print("File dump: --------------------------------------------------->")
print("\n\n\n---------------------------------------------------> " + file.filename + "\n\n")
print("\n".join(lines) + "\n")
print("<---------------------------------------------------- " + file.filename + " ends.")
print("");
print("<---------------------------------------------------- " + self.sourcefile.filename)
print("")
return
if line in lines[current_line]:
current_line += 1

View File

@@ -115,7 +115,7 @@ declare i1 @llvm.expect.i1(i1, i1)
!14 = !DILocalVariable(name: "x", scope: !6, file: !5, line: 13, type: !11, align: 4)
!15 = !DILocation(line: 13, column: 6, scope: !6)
!16 = !DILocation(line:
!17 = distinct !DISubprogram(name: "@atomic_load", linkageName: "@atomic_load", scope: !18, file: !18,
!17 = distinct !DISubprogram(name: "@atomic_load",
!18 = !DIFile(filename: "mem.c3",
!19 = !DILocation(line: 13, column: 10, scope: !6)
!20 = !DILocalVariable(name: "y", scope: !6, file: !5, line: 14, type: !11, align: 4)
@@ -125,13 +125,13 @@ declare i1 @llvm.expect.i1(i1, i1)
!24 = !DILocation(line: 14, column: 10, scope: !6)
!25 = !DILocation(line: 15, column: 25, scope: !6)
!26 = !DILocation(line: 15, column: 19, scope: !6)
!27 = !DILocation(line: 212, column: 20, scope: !28, inlinedAt: !29)
!27 = !DILocation(
!28 = distinct !DISubprogram(name: "@atomic_store", linkageName: "@atomic_store", scope: !18
!29 = !DILocation(line: 15, column: 2, scope: !6)
!30 = !DILocation(line: 16, column: 24, scope: !6)
!31 = !DILocation(line: 16, column: 19, scope: !6)
!32 = !DILocation(line: 212, column: 20, scope: !33, inlinedAt: !34)
!33 = distinct !DISubprogram(name: "@atomic_store", linkageName: "@atomic_store", scope: !18, file: !18, line: 210, scopeLine: 210, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !4
!32 = !DILocation(
!33 = distinct !DISubprogram(name: "@atomic_store", linkageName: "@atomic_store", scope: !18
!34 = !DILocation(line: 16, column: 2, scope: !6)
!35 = !DILocation(line: 17, column: 20, scope: !6)
!36 = !DILocation(line: 17, column: 6, scope: !6)

View File

@@ -653,9 +653,8 @@ no_match: ; preds = %compare
!69 = !DILocation(line: 33, column: 49, scope: !63)
!70 = !DILocalVariable(name: "name", arg: 3, scope: !63, file: !5, line: 33, type: !37)
!71 = !DILocation(line: 33, column: 63, scope: !63)
!72 = !DILocation(line: 564, column: 10, scope: !73, inlinedAt: !75)
!73 = distinct !DISubprogram(name: "new", linkageName: "new", scope: !74, file: !74, line: 561, scopeLine: 561, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition
!72 = !DILocation(line:
!73 = distinct !DISubprogram(name: "new", linkageName: "new", scope: !74, file: !74
!75 = !DILocation(line: 34, column: 15, scope: !63)
!76 = distinct !DISubprogram(name: "test", linkageName: "test.test", scope: !5, file: !5, line: 41, type: !77, scopeLine: 41, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition
!77 = !DISubroutineType(types: !78)
@@ -728,9 +727,10 @@ no_match: ; preds = %compare
!147 = !DILocation(line: 24, column: 43, scope: !144, inlinedAt: !146)
!148 = !DILocation(line: 226, column: 55, scope: !149, inlinedAt: !151)
!151 = !DILocation(line: 216, column: 9, scope: !152, inlinedAt: !153)
!152 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !150, file: !150, line: 214, scopeLine: 214, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition
!153 = !DILocation(line: 649, column: 20, scope: !154, inlinedAt: !155)
!154 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !74, file: !74, line: 647, scopeLine: 647, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition
!152 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !150, file: !150
!153 = !DILocation(line:
!154 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !74, file: !74
!155 = !DILocation(line:
!156 = !DILocation(line: 226, column: 40, scope: !149, inlinedAt: !151)
!157 = !DILocation(line: 62, column: 7, scope: !158, inlinedAt: !159)
!158 = distinct !DISubprogram(name: "malloc_try", linkageName: "malloc_try", scope: !150, file: !150, line: 60, scopeLine: 60, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition