-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[RISC-V] New ABI classifiers #101114
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
[RISC-V] New ABI classifiers #101114
Changes from 4 commits
7a90c59
8c76b09
f078e9b
68049e9
9ce8cab
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 |
|---|---|---|
|
|
@@ -24,4 +24,154 @@ const regNumber fltArgRegs [] = {REG_FLTARG_0, REG_FLTARG_1, REG_FLTARG_2, REG_F | |
| const regMaskTP fltArgMasks[] = {RBM_FLTARG_0, RBM_FLTARG_1, RBM_FLTARG_2, RBM_FLTARG_3, RBM_FLTARG_4, RBM_FLTARG_5, RBM_FLTARG_6, RBM_FLTARG_7 }; | ||
| // clang-format on | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // RiscV64Classifier: | ||
| // Construct a new instance of the RISC-V 64 ABI classifier. | ||
| // | ||
| // Parameters: | ||
| // info - Info about the method being classified. | ||
| // | ||
| RiscV64Classifier::RiscV64Classifier(const ClassifierInfo& info) | ||
| : m_info(info) | ||
| , m_intRegs(intArgRegs, ArrLen(intArgRegs)) | ||
| , m_floatRegs(fltArgRegs, ArrLen(fltArgRegs)) | ||
| { | ||
| } | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Classify: | ||
| // Classify a parameter for the RISC-V 64 ABI. | ||
| // | ||
| // Parameters: | ||
| // comp - Compiler instance | ||
| // type - The type of the parameter | ||
| // structLayout - The layout of the struct. Expected to be non-null if | ||
| // varTypeIsStruct(type) is true. | ||
| // wellKnownParam - Well known type of the parameter (if it may affect its ABI classification) | ||
| // | ||
| // Returns: | ||
| // Classification information for the parameter. | ||
| // | ||
| ABIPassingInformation RiscV64Classifier::Classify(Compiler* comp, | ||
| var_types type, | ||
| ClassLayout* structLayout, | ||
| WellKnownArg /*wellKnownParam*/) | ||
| { | ||
| assert(!m_info.IsVarArgs); // TODO: varargs currently not supported on RISC-V | ||
|
|
||
| StructFloatFieldInfoFlags flags = STRUCT_NO_FLOAT_FIELD; | ||
| unsigned intFields = 0, floatFields = 0; | ||
| unsigned passedSize; | ||
|
|
||
| if (varTypeIsStruct(type)) | ||
| { | ||
| passedSize = structLayout->GetSize(); | ||
| if (passedSize > MAX_PASS_MULTIREG_BYTES) | ||
| { | ||
| passedSize = TARGET_POINTER_SIZE; // pass by reference | ||
| } | ||
| else if (!structLayout->IsBlockLayout()) | ||
| { | ||
| flags = (StructFloatFieldInfoFlags)comp->info.compCompHnd->getRISCV64PassStructInRegisterFlags( | ||
| structLayout->GetClassHandle()); | ||
|
|
||
| if ((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0) | ||
| { | ||
| floatFields = 1; | ||
| } | ||
| else if ((flags & STRUCT_FLOAT_FIELD_ONLY_TWO) != 0) | ||
| { | ||
| floatFields = 2; | ||
| } | ||
| else if (flags != STRUCT_NO_FLOAT_FIELD) | ||
| { | ||
| assert((flags & (STRUCT_FLOAT_FIELD_FIRST | STRUCT_FLOAT_FIELD_SECOND)) != 0); | ||
| floatFields = 1; | ||
| intFields = 1; | ||
| } | ||
| } | ||
| } | ||
| else | ||
| { | ||
| assert(genTypeSize(type) <= TARGET_POINTER_SIZE); | ||
|
|
||
| if (varTypeIsFloating(type)) | ||
| floatFields = 1; | ||
|
|
||
| passedSize = genTypeSize(type); | ||
| } | ||
|
|
||
| assert((floatFields > 0) || (intFields == 0)); | ||
|
|
||
| auto PassSlot = [this](bool inFloatReg, unsigned offset, unsigned size) -> ABIPassingSegment { | ||
|
Member
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. Nit: Most places within the JIT that use lambdas use camelCase naming convention. No need to address this here. |
||
| assert(size > 0); | ||
| assert(size <= TARGET_POINTER_SIZE); | ||
| if (inFloatReg) | ||
| { | ||
| return ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), offset, size); | ||
| } | ||
| else if (m_intRegs.Count() > 0) | ||
| { | ||
| return ABIPassingSegment::InRegister(m_intRegs.Dequeue(), offset, size); | ||
| } | ||
| else | ||
| { | ||
| assert((m_stackArgSize % TARGET_POINTER_SIZE) == 0); | ||
| ABIPassingSegment seg = ABIPassingSegment::OnStack(m_stackArgSize, offset, size); | ||
| m_stackArgSize += TARGET_POINTER_SIZE; | ||
| return seg; | ||
| } | ||
| }; | ||
|
|
||
| if ((floatFields > 0) && (m_floatRegs.Count() >= floatFields) && (m_intRegs.Count() >= intFields)) | ||
| { | ||
| // Hardware floating-point calling convention | ||
| if ((floatFields == 1) && (intFields == 0)) | ||
| { | ||
| if (flags == STRUCT_NO_FLOAT_FIELD) | ||
| assert(varTypeIsFloating(type)); // standalone floating-point real | ||
| else | ||
| assert((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) != 0); // struct containing just one FP real | ||
|
|
||
| return ABIPassingInformation::FromSegment(comp, ABIPassingSegment::InRegister(m_floatRegs.Dequeue(), 0, | ||
| passedSize)); | ||
| } | ||
| else | ||
| { | ||
| assert(varTypeIsStruct(type)); | ||
| assert((floatFields + intFields) == 2); | ||
| assert(flags != STRUCT_NO_FLOAT_FIELD); | ||
| assert((flags & STRUCT_FLOAT_FIELD_ONLY_ONE) == 0); | ||
|
|
||
| unsigned firstSize = ((flags & STRUCT_FIRST_FIELD_SIZE_IS8) != 0) ? 8 : 4; | ||
| unsigned secondSize = ((flags & STRUCT_SECOND_FIELD_SIZE_IS8) != 0) ? 8 : 4; | ||
| unsigned offset = max(firstSize, secondSize); // TODO: cover empty fields and custom offsets / alignments | ||
|
|
||
| bool isFirstFloat = (flags & (STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_FIRST)) != 0; | ||
| bool isSecondFloat = (flags & (STRUCT_FLOAT_FIELD_ONLY_TWO | STRUCT_FLOAT_FIELD_SECOND)) != 0; | ||
| assert(isFirstFloat || isSecondFloat); | ||
|
|
||
| return ABIPassingInformation::FromSegments(comp, {PassSlot(isFirstFloat, 0, firstSize), | ||
| PassSlot(isSecondFloat, offset, secondSize)}); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| // Integer calling convention | ||
| if (passedSize <= TARGET_POINTER_SIZE) | ||
| { | ||
| return ABIPassingInformation::FromSegment(comp, PassSlot(false, 0, passedSize)); | ||
| } | ||
| else | ||
| { | ||
| assert(varTypeIsStruct(type)); | ||
| return ABIPassingInformation::FromSegments(comp, {PassSlot(false, 0, TARGET_POINTER_SIZE), | ||
| PassSlot(false, TARGET_POINTER_SIZE, | ||
| passedSize - TARGET_POINTER_SIZE)}); | ||
| } | ||
| } | ||
|
|
||
| unreached(); | ||
|
Member
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. Does this do anything? Won't we have a compiler error if this becomes accidentally reachable? Feel free to remove this separately. |
||
| } | ||
|
|
||
| #endif // TARGET_RISCV64 | ||
Uh oh!
There was an error while loading. Please reload this page.