-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[RISC-V] Add CSR read/write builtins #85091
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py | ||
// RUN: %clang_cc1 -triple riscv32 -target-feature +zicsr %s -fsyntax-only -verify | ||
// RUN: %clang_cc1 -triple riscv64 -target-feature +zicsr %s -fsyntax-only -verify | ||
// RUN: %clang_cc1 -triple riscv32 %s -fsyntax-only -verify | ||
|
||
#ifdef __riscv_zicsr | ||
unsigned long non_const(unsigned long a) { | ||
return __builtin_riscv_csrr(a); // expected-error {{argument to '__builtin_riscv_csrr' must be a constant integer}} | ||
} | ||
|
||
unsigned long too_large() { | ||
return __builtin_riscv_csrr(33312); // expected-error {{argument value 33312 is outside the valid range [0, 4095]}} | ||
} | ||
|
||
void non_const_write(unsigned long d) { | ||
return __builtin_riscv_csrw(d, d); // expected-error {{argument to '__builtin_riscv_csrw' must be a constant integer}} | ||
} | ||
#else | ||
unsigned long read(unsigned long a) { | ||
return __builtin_riscv_csrr(3); // expected-error {{builtin requires at least one of the following extensions: 'Zicsr'}} | ||
} | ||
void write(unsigned long d) { | ||
return __builtin_riscv_csrw(3, d); // expected-error {{builtin requires at least one of the following extensions: 'Zicsr'}} | ||
} | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py | ||
// RUN: %clang_cc1 -triple riscv32 -target-feature +zicsr -emit-llvm %s -o - \ | ||
// RUN: -disable-O0-optnone | opt -S -passes=mem2reg \ | ||
// RUN: | FileCheck %s -check-prefix=RV32ZICSR | ||
// RUN: %clang_cc1 -triple riscv64 -target-feature +zicsr -emit-llvm %s -o - \ | ||
// RUN: -disable-O0-optnone | opt -S -passes=mem2reg \ | ||
// RUN: | FileCheck %s -check-prefix=RV64ZICSR | ||
|
||
// RV32ZICSR-LABEL: @readcsr( | ||
// RV32ZICSR-NEXT: entry: | ||
// RV32ZICSR-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.csrr(i32 3) | ||
// RV32ZICSR-NEXT: ret i32 [[TMP0]] | ||
// | ||
// RV64ZICSR-LABEL: @readcsr( | ||
// RV64ZICSR-NEXT: entry: | ||
// RV64ZICSR-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.csrr64(i64 3) | ||
// RV64ZICSR-NEXT: ret i64 [[TMP0]] | ||
// | ||
unsigned long readcsr() { | ||
return __builtin_riscv_csrr(3); | ||
} | ||
|
||
// RV32ZICSR-LABEL: @readcsr_arbitrary( | ||
// RV32ZICSR-NEXT: entry: | ||
// RV32ZICSR-NEXT: [[TMP0:%.*]] = call i32 @llvm.riscv.csrr(i32 333) | ||
// RV32ZICSR-NEXT: ret i32 [[TMP0]] | ||
// | ||
// RV64ZICSR-LABEL: @readcsr_arbitrary( | ||
// RV64ZICSR-NEXT: entry: | ||
// RV64ZICSR-NEXT: [[TMP0:%.*]] = call i64 @llvm.riscv.csrr64(i64 333) | ||
// RV64ZICSR-NEXT: ret i64 [[TMP0]] | ||
// | ||
unsigned long readcsr_arbitrary() { | ||
return __builtin_riscv_csrr(333); | ||
} | ||
|
||
// RV32ZICSR-LABEL: @writecsr( | ||
// RV32ZICSR-NEXT: entry: | ||
// RV32ZICSR-NEXT: call void @llvm.riscv.csrw(i32 3, i32 [[D:%.*]]) | ||
// RV32ZICSR-NEXT: ret void | ||
// | ||
// RV64ZICSR-LABEL: @writecsr( | ||
// RV64ZICSR-NEXT: entry: | ||
// RV64ZICSR-NEXT: call void @llvm.riscv.csrw64(i64 3, i64 [[D:%.*]]) | ||
// RV64ZICSR-NEXT: ret void | ||
// | ||
void writecsr(unsigned long d) { | ||
return __builtin_riscv_csrw(3, d); | ||
} | ||
|
||
// RV32ZICSR-LABEL: @writecsr_arbitrary( | ||
// RV32ZICSR-NEXT: entry: | ||
// RV32ZICSR-NEXT: call void @llvm.riscv.csrw(i32 333, i32 [[D:%.*]]) | ||
// RV32ZICSR-NEXT: ret void | ||
// | ||
// RV64ZICSR-LABEL: @writecsr_arbitrary( | ||
// RV64ZICSR-NEXT: entry: | ||
// RV64ZICSR-NEXT: call void @llvm.riscv.csrw64(i64 333, i64 [[D:%.*]]) | ||
// RV64ZICSR-NEXT: ret void | ||
// | ||
void writecsr_arbitrary(unsigned long d) { | ||
return __builtin_riscv_csrw(333, d); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,6 +74,21 @@ let TargetPrefix = "riscv" in { | |
|
||
} // TargetPrefix = "riscv" | ||
|
||
let TargetPrefix = "riscv" in { | ||
// Zicsr | ||
def int_riscv_csrr : | ||
DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], | ||
[IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>]>; | ||
def int_riscv_csrr64 : | ||
DefaultAttrsIntrinsic<[llvm_i64_ty], [llvm_i64_ty], | ||
[IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>]>; | ||
def int_riscv_csrw : | ||
DefaultAttrsIntrinsic<[], [llvm_i32_ty, llvm_i32_ty], | ||
[IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>]>; | ||
def int_riscv_csrw64 : | ||
DefaultAttrsIntrinsic<[], [llvm_i64_ty, llvm_i64_ty], | ||
[IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>]>; | ||
} // TargetPrefix = "riscv" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about CSR swap? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TBH, I only implemented these two initially for 2 reasons
I think ultimately, we could provide read, write, set, clear and swap (and handle producing the immediate forms if the operand allows it). |
||
//===----------------------------------------------------------------------===// | ||
// Bitmanip (Bit Manipulation) Extension | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | ||
; RUN: llc -mtriple=riscv32 -mattr=+zicsr -verify-machineinstrs < %s \ | ||
; RUN: | FileCheck %s -check-prefix=RV32ZICSR | ||
|
||
declare i32 @llvm.riscv.csrr(i32 immarg) | ||
declare void @llvm.riscv.csrw(i32 immarg, i32) | ||
|
||
define i32 @read() nounwind { | ||
; RV32ZICSR-LABEL: read: | ||
; RV32ZICSR: # %bb.0: | ||
; RV32ZICSR-NEXT: csrr a0, fcsr | ||
; RV32ZICSR-NEXT: csrr a1, fcsr | ||
; RV32ZICSR-NEXT: csrr a2, stval | ||
; RV32ZICSR-NEXT: add a1, a1, a2 | ||
; RV32ZICSR-NEXT: add a0, a0, a1 | ||
; RV32ZICSR-NEXT: ret | ||
%val = call i32 @llvm.riscv.csrr(i32 3) | ||
%val2 = call i32 @llvm.riscv.csrr(i32 3) | ||
%val3 = call i32 @llvm.riscv.csrr(i32 323) | ||
%add = add i32 %val2, %val3 | ||
%ret = add i32 %val, %add | ||
ret i32 %ret | ||
} | ||
|
||
define void @testwrite(i32 %d) nounwind { | ||
; RV32ZICSR-LABEL: testwrite: | ||
; RV32ZICSR: # %bb.0: | ||
; RV32ZICSR-NEXT: csrw fcsr, a0 | ||
; RV32ZICSR-NEXT: csrw 3435, a0 | ||
; RV32ZICSR-NEXT: ret | ||
call void @llvm.riscv.csrw(i32 3, i32 %d) | ||
call void @llvm.riscv.csrw(i32 3435, i32 %d) | ||
ret void | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | ||
; RUN: llc -mtriple=riscv64 -mattr=+zicsr -verify-machineinstrs < %s \ | ||
; RUN: | FileCheck %s | ||
|
||
declare i64 @llvm.riscv.csrr64(i64 immarg) | ||
declare void @llvm.riscv.csrw64(i64 immarg, i64) | ||
|
||
define i64 @read() nounwind { | ||
; CHECK-LABEL: read: | ||
; CHECK: # %bb.0: | ||
; CHECK-NEXT: csrr a0, fcsr | ||
; CHECK-NEXT: csrr a1, fcsr | ||
; CHECK-NEXT: csrr a2, 111 | ||
; CHECK-NEXT: add a1, a1, a2 | ||
; CHECK-NEXT: add a0, a0, a1 | ||
; CHECK-NEXT: ret | ||
%val = call i64 @llvm.riscv.csrr64(i64 3) | ||
%val2 = call i64 @llvm.riscv.csrr64(i64 3) | ||
%val3 = call i64 @llvm.riscv.csrr64(i64 111) | ||
%add = add i64 %val2, %val3 | ||
%ret = add i64 %val, %add | ||
ret i64 %ret | ||
} | ||
|
||
define void @testwrite(i64 %d) nounwind { | ||
; CHECK-LABEL: testwrite: | ||
; CHECK: # %bb.0: | ||
; CHECK-NEXT: csrw fcsr, a0 | ||
; CHECK-NEXT: csrw 3231, a0 | ||
; CHECK-NEXT: ret | ||
call void @llvm.riscv.csrw64(i64 3, i64 %d) | ||
call void @llvm.riscv.csrw64(i64 3231, i64 %d) | ||
ret void | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want "size_t" or "uintptr_t", please use that, not "unsigned long".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think these are
Const
since they operate on state that is not part of their arguments/return.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can certainly change it to
size_t
. And I'll move them out of the section marked withConst
.