├── docs ├── README.mkd ├── 05-disassembly.mkd ├── 10-codegen-frame-handling.mkd ├── 11-codegen-calling-convention.mkd ├── 09-codegen-branches-and-function-calls.mkd ├── 06-relocations-and-fixups.mkd ├── 04-instruction-printer-and-testing.mkd ├── 08-codegen-memory-operations.mkd ├── 02-starting-the-backend.mkd ├── 01-intro-and-building-llvm.mkd ├── 07-initial-codegen.mkd └── 03-assembly-parsing.mkd ├── 0059-RISCV-Add-xfailed-test-case-for-type-legalisation-fa.patch ├── 0060-Add-xfailed-RV32D-test-case-failing-with-multiple-vr.patch ├── 0074-RISCV-Implement-isLegalICmpImmediate.patch ├── 0073-RISCV-Implement-isLegalAddImmediate.patch ├── 0012-Add-RISC-V-support-to-update_llc_test_checks.py.patch ├── 0076-RISCV-Implement-isZExtFree.patch ├── 0045-LegalizeDAG-promote-frameaddr-returnaddr-arguments-t.patch ├── 0085-RISCV-Set-AllowRegisterRenaming-1.patch ├── 0046-LegalizeDAG-promote-PREFETCH-operands-to-native-inte.patch ├── 0077-RISCV-Implement-computeKnownBitsForTargetNode-for-RI.patch ├── 0072-RISCV-Implement-isLegalAddressingMode-for-RISC-V.patch ├── 0075-RISCV-Implement-isTruncateFree.patch ├── 0071-RISCV-Expose-options-to-enable-optimisation-of-compl.patch ├── 0038-RISCV-MC-layer-support-for-the-standard-RV64M-instru.patch ├── 0078-RISCV-Implement-isLoadFromStackSlot-and-isStoreToSta.patch ├── 0053-RISCV-WIP-Codegen-support-for-RV32F-fused-multiply-a.patch ├── 0081-RISCV-Define-getSetCCResultType-for-setting-vector-s.patch ├── 0024-RISCV-Allow-lowering-of-dynamic_stackalloc-stacksave.patch ├── 0079-RISCV-Allow-RISCVAsmBackend-writeNopData-to-generate.patch ├── 0014-RISCV-Codegen-support-for-materializing-constants.patch ├── 0051-RISCV-Codegen-support-for-FPR32-stack-loads-stores.patch ├── 0056-RISCV-Codegen-support-for-RV32D-floating-point-conve.patch ├── scripts └── run_torture_suite.sh ├── 0064-RISCV-MC-layer-support-for-the-instructions-added-in.patch ├── 0040-RISCV-MC-layer-support-for-the-standard-RV64F-instru.patch ├── 0047-RISCV-Initial-support-for-emitting-call-frame-inform.patch ├── 0041-RISCV-MC-layer-support-for-the-standard-RV64D-instru.patch ├── 0055-RISCV-Add-codegen-support-for-RV32D-floating-point-a.patch ├── 0033-RISCV-MC-layer-support-for-the-standard-RV32M-instru.patch ├── 0029-RISCV-Add-support-for-llvm.-frameaddress-returnaddre.patch ├── 0054-RISCV-Add-minimum-necessary-for-RV32D-codegen-for-fa.patch ├── 0083-RISCV-Add-ELFObjectFileBase-getRISCVFeatures-let-llv.patch ├── 0002-RISCV-Recognise-riscv32-and-riscv64-in-triple-parsin.patch ├── 0066-RISCV-Implement-RISCVRegisterInfo-enableMultipleCopy.patch ├── 0021-RISCV-Use-register-X0-ZERO-for-constant-0.patch ├── 0080-RISCV-Encode-RISCV-specific-ELF-e_flags-to-RISCV-Bin.patch └── 0032-RISCV-Reserve-an-emergency-spill-slot-for-the-regist.patch /docs/README.mkd: -------------------------------------------------------------------------------- 1 | Documentation is shared here in the spirit of "release early, release often". 2 | It will soon be posted to lowrisc.org. Please wait until then before spreading 3 | more widely. 4 | 5 | The codegen documentation in particular could do with further expansion so it 6 | is more accessible to those who are new to LLVM. 7 | 8 | Files in this directory are placed under the Creative Commons CC-BY-SA 4.0 9 | license . 10 | -------------------------------------------------------------------------------- /docs/05-disassembly.mkd: -------------------------------------------------------------------------------- 1 | # Supporting disassembly 2 | 3 | RISCVDisassembler provides methods for decoding immediates and registers to 4 | appropriate `MCOperand` instances. This is driven by `getInstruction`, which 5 | in turn relies on the TableGen-produced `decodeInstruction`. 6 | 7 | For instance: 8 | 9 | template 10 | static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm, 11 | int64_t Address, const void *Decoder) 12 | assert(isUInt(Imm) && "Invalid immediate"); 13 | // Sign-extend the number in the bottom N bits of Imm 14 | Inst.addOperand(MCOperand::createImm(SignExtend64(Imm))); 15 | return MCDisassembler::Success; 16 | } 17 | 18 | These `decode*` methods are specified in `RISCVInstrInfo.td`. 19 | 20 | With disassembly support implemented, `rv32i-valid.s` can be extended to 21 | support full round-trip testing, i.e. checking that the `CHECK-INST` lines are 22 | correct both for `llvm-mc -show-encoding` and when using `llvm-objdump -d` to 23 | disassemble the object file. 24 | -------------------------------------------------------------------------------- /0059-RISCV-Add-xfailed-test-case-for-type-legalisation-fa.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Add xfailed test-case for type legalisation failure 4 | 5 | --- 6 | test/CodeGen/RISCV/double-intrinsics.ll | 13 +++++++++++++ 7 | 1 file changed, 13 insertions(+) 8 | create mode 100644 test/CodeGen/RISCV/double-intrinsics.ll 9 | 10 | diff --git a/test/CodeGen/RISCV/double-intrinsics.ll b/test/CodeGen/RISCV/double-intrinsics.ll 11 | new file mode 100644 12 | index 00000000000..99250a8363b 13 | --- /dev/null 14 | +++ b/test/CodeGen/RISCV/double-intrinsics.ll 15 | @@ -0,0 +1,13 @@ 16 | +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ 17 | +; RUN: | FileCheck -check-prefix=RV32IFD %s 18 | +; XFAIL: * 19 | + 20 | +declare double @llvm.floor.f64(double) 21 | + 22 | +; Generates a bitcast to the illegal i64 type while lowering a libcall to 23 | +; ffloor. 24 | + 25 | +define double @foo(double %a) nounwind { 26 | + %1 = call double @llvm.floor.f64(double %a) 27 | + ret double %1 28 | +} 29 | -- 30 | 2.16.2 31 | 32 | -------------------------------------------------------------------------------- /0060-Add-xfailed-RV32D-test-case-failing-with-multiple-vr.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: Add xfailed RV32D test case, failing with multiple vreg definitions 4 | 5 | --- 6 | .../RISCV/double-fail-multiple-vreg-defs.ll | 30 ++++++++++++++++++++++ 7 | 1 file changed, 30 insertions(+) 8 | create mode 100644 test/CodeGen/RISCV/double-fail-multiple-vreg-defs.ll 9 | 10 | diff --git a/test/CodeGen/RISCV/double-fail-multiple-vreg-defs.ll b/test/CodeGen/RISCV/double-fail-multiple-vreg-defs.ll 11 | new file mode 100644 12 | index 00000000000..3ab034ccfc5 13 | --- /dev/null 14 | +++ b/test/CodeGen/RISCV/double-fail-multiple-vreg-defs.ll 15 | @@ -0,0 +1,30 @@ 16 | +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ 17 | +; RUN: | FileCheck -check-prefix=RV32IFD %s 18 | +; XFAIL: * 19 | + 20 | +define double @test(double %a) nounwind { 21 | + ret double %a 22 | +} 23 | + 24 | +define i32 @main() nounwind { 25 | +entry: 26 | +; Note: test succeeds if loading the double from a global rather than calling 27 | +; 'test' 28 | + %call = call double @test(double 2.000000e+00) 29 | + %cmp = fcmp olt double %call, 2.400000e-01 30 | + %cmp2 = fcmp ogt double %call, 2.600000e-01 31 | + %or.cond = or i1 %cmp, %cmp2 32 | + br i1 %or.cond, label %if.then, label %if.end 33 | + 34 | +if.then: ; preds = %entry 35 | + call void @abort() 36 | + unreachable 37 | + 38 | +if.end: ; preds = %entry 39 | + call void @exit(i32 0) 40 | + unreachable 41 | +} 42 | + 43 | +declare void @abort() 44 | + 45 | +declare void @exit(i32) 46 | -- 47 | 2.16.2 48 | 49 | -------------------------------------------------------------------------------- /0074-RISCV-Implement-isLegalICmpImmediate.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement isLegalICmpImmediate 4 | 5 | No change in codegen for the torture suite, some minor changes for small 6 | benchmark set. 7 | --- 8 | lib/Target/RISCV/RISCVISelLowering.cpp | 4 ++++ 9 | lib/Target/RISCV/RISCVISelLowering.h | 1 + 10 | 2 files changed, 5 insertions(+) 11 | 12 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 13 | index 9ab1270f2f8..a9f9f5c7d56 100644 14 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | @@ -173,6 +173,10 @@ bool RISCVTargetLowering::isLegalAddressingMode(const DataLayout &DL, 17 | return true; 18 | } 19 | 20 | +bool RISCVTargetLowering::isLegalICmpImmediate(int64_t Imm) const { 21 | + return isInt<12>(Imm); 22 | +} 23 | + 24 | bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm) const { 25 | return isInt<12>(Imm); 26 | } 27 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 28 | index eae01bae883..17183004df6 100644 29 | --- a/lib/Target/RISCV/RISCVISelLowering.h 30 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 31 | @@ -40,6 +40,7 @@ public: 32 | bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, 33 | unsigned AS, 34 | Instruction *I = nullptr) const override; 35 | + bool isLegalICmpImmediate(int64_t Imm) const override; 36 | bool isLegalAddImmediate(int64_t Imm) const override; 37 | 38 | // Provide custom lowering hooks for some operations. 39 | -- 40 | 2.16.2 41 | 42 | -------------------------------------------------------------------------------- /docs/10-codegen-frame-handling.mkd: -------------------------------------------------------------------------------- 1 | # Codegen for frame handling 2 | 3 | The RISC-V backend is now able to lower function calls, but doesn't yet 4 | generate function prolog/epilog or correctly lower FrameIndex references. 5 | 6 | ## Lowering FrameIndex 7 | 8 | First, define a dummy "addressing mode". This matches a frameindex, and is 9 | necessary as as a frameindex can't be matched directly in a pattern. 10 | 11 | def AddrFI : ComplexPattern; 12 | 13 | def : Pat<(LoadOp (add AddrFI:$rs1, simm12:$imm12)), 14 | (Inst AddrFI:$rs1, simm12:$imm12)>; 15 | def : Pat<(LoadOp (IsOrAdd AddrFI:$rs1, simm12:$imm12)), 16 | (Inst AddrFI:$rs1, simm12:$imm12)>; 17 | 18 | Modify `RISCVDAGToDAGISel::Select` so it lowers `ISD::FrameIndex` to an `ADDI` 19 | with appropriate operands: 20 | 21 | if (Opcode == ISD::FrameIndex) { 22 | SDLoc DL(Node); 23 | SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT); 24 | int FI = dyn_cast(Node)->getIndex(); 25 | EVT VT = Node->getValueType(0); 26 | SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 27 | ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm)); 28 | return; 29 | } 30 | 31 | Finally, `RISCVFrameLowering::getFrameIndexReference` must be implemented. 32 | This must select the correct frame register and offset. Callee-save registers 33 | are referenced relative to the stack pointer, otherwise the frame pointer is 34 | used. 35 | 36 | ## Prolog and epilog insertion 37 | 38 | `RISCVFrameLowering::emitPrologue` and `RISCVFrameLowering::emitEpilogue` were 39 | previously stubbed out, but must now allocate and deallocate space on the 40 | stack, and manipulate the frame pointer appropriately. 41 | 42 | -------------------------------------------------------------------------------- /0073-RISCV-Implement-isLegalAddImmediate.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement isLegalAddImmediate 4 | 5 | There are some very minor codegen changes in a small subset of the GCC torture 6 | suite. 7 | --- 8 | lib/Target/RISCV/RISCVISelLowering.cpp | 4 ++++ 9 | lib/Target/RISCV/RISCVISelLowering.h | 1 + 10 | 2 files changed, 5 insertions(+) 11 | 12 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 13 | index e9c003aeba9..9ab1270f2f8 100644 14 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | @@ -173,6 +173,10 @@ bool RISCVTargetLowering::isLegalAddressingMode(const DataLayout &DL, 17 | return true; 18 | } 19 | 20 | +bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm) const { 21 | + return isInt<12>(Imm); 22 | +} 23 | + 24 | // Changes the condition code and swaps operands if necessary, so the SetCC 25 | // operation matches one of the comparisons supported directly in the RISC-V 26 | // ISA. 27 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 28 | index e7dd46fc835..eae01bae883 100644 29 | --- a/lib/Target/RISCV/RISCVISelLowering.h 30 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 31 | @@ -40,6 +40,7 @@ public: 32 | bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, 33 | unsigned AS, 34 | Instruction *I = nullptr) const override; 35 | + bool isLegalAddImmediate(int64_t Imm) const override; 36 | 37 | // Provide custom lowering hooks for some operations. 38 | SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; 39 | -- 40 | 2.16.2 41 | 42 | -------------------------------------------------------------------------------- /0012-Add-RISC-V-support-to-update_llc_test_checks.py.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: Add RISC-V support to update_llc_test_checks.py 4 | 5 | --- 6 | utils/UpdateTestChecks/asm.py | 18 ++++++++++++++++++ 7 | 1 file changed, 18 insertions(+) 8 | 9 | diff --git a/utils/UpdateTestChecks/asm.py b/utils/UpdateTestChecks/asm.py 10 | index 4a1c9d7b00b..c98dfc9eeac 100644 11 | --- a/utils/UpdateTestChecks/asm.py 12 | +++ b/utils/UpdateTestChecks/asm.py 13 | @@ -54,6 +54,12 @@ ASM_FUNCTION_PPC_RE = re.compile( 14 | r'.Lfunc_end[0-9]+:\n', 15 | flags=(re.M | re.S)) 16 | 17 | +ASM_FUNCTION_RISCV_RE = re.compile( 18 | + r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' 19 | + r'(?P^##?[ \t]+[^:]+:.*?)\s*' 20 | + r'.Lfunc_end[0-9]+:\n', 21 | + flags=(re.M | re.S)) 22 | + 23 | ASM_FUNCTION_SYSTEMZ_RE = re.compile( 24 | r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n' 25 | r'[ \t]+.cfi_startproc\n' 26 | @@ -131,6 +137,16 @@ def scrub_asm_mips(asm, args): 27 | asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 28 | return asm 29 | 30 | +def scrub_asm_riscv(asm, args): 31 | + # Scrub runs of whitespace out of the assembly, but leave the leading 32 | + # whitespace in place. 33 | + asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) 34 | + # Expand the tabs used for indentation. 35 | + asm = string.expandtabs(asm, 2) 36 | + # Strip trailing whitespace. 37 | + asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) 38 | + return asm 39 | + 40 | def scrub_asm_systemz(asm, args): 41 | # Scrub runs of whitespace out of the assembly, but leave the leading 42 | # whitespace in place. 43 | @@ -173,6 +189,8 @@ def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, pre 44 | 'mips': (scrub_asm_mips, ASM_FUNCTION_MIPS_RE), 45 | 'powerpc64': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE), 46 | 'powerpc64le': (scrub_asm_powerpc64, ASM_FUNCTION_PPC_RE), 47 | + 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 48 | + 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 49 | 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE), 50 | } 51 | handlers = None 52 | -- 53 | 2.16.2 54 | 55 | -------------------------------------------------------------------------------- /docs/11-codegen-calling-convention.mkd: -------------------------------------------------------------------------------- 1 | # Supporting the RISC-V calling convention 2 | 3 | Although the tablegen-specified calling convention will work for simple cases, 4 | it fails to represent the complete set of rules that describe the [RISC-V 5 | calling 6 | convention](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md). 7 | `CC_RISCV` implements the RISC-V calling convention. It is passed each 8 | argument in pieces, after it has been legalised. For instance, an `i64` will 9 | be split to a pair of `i32`. Therefore, `CC_RISCV` contains logic to track 10 | such split values to determine if the original argument's size indicates it 11 | should be passed in registers or on the stack. 12 | 13 | The expectations for frontend ABI lowering vary from target to target. 14 | Ideally, an LLVM frontend would be able to avoid worrying about many ABI 15 | details, but this is a longer term goal. For now, we simply try to keep the 16 | role of the frontend as simple and well-defined as possible. The rules can 17 | be summarised as: 18 | 19 | * Never split up large scalar arguments. We handle them here. 20 | * If a hardfloat calling convention is being used, and the struct may be 21 | passed in a pair of registers (fp+fp, int+fp), and both registers are 22 | available, then pass as two separate arguments. If either the GPRs or FPRs 23 | are exhausted, then pass according to the rule below. 24 | * If a struct could never be passed in registers or directly in a stack 25 | slot (as it is larger than `2*XLEN` and the floating point rules don't 26 | apply), then pass it using a pointer with the byval attribute. 27 | * If a struct is less than `2*XLEN`, then coerce to either a two-element 28 | word-sized array or a `2*XLEN` scalar (depending on alignment). 29 | * The frontend can determine whether a struct is returned by reference or 30 | not based on its size and fields. If it will be returned by reference, the 31 | frontend must modify the prototype so a pointer with the sret annotation is 32 | passed as the first argument. This is not necessary for large scalar 33 | returns. 34 | * Struct return values and varargs should be coerced to structs containing 35 | register-size fields in the same situations they would be for fixed 36 | arguments. 37 | 38 | 39 | -------------------------------------------------------------------------------- /0076-RISCV-Implement-isZExtFree.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement isZExtFree 4 | 5 | Returns true if it's a load, where we know LBU/LHU/LWU will be selected. Saves 6 | a number of unnecessary zexts across the torture suite. 7 | --- 8 | lib/Target/RISCV/RISCVISelLowering.cpp | 14 ++++++++++++++ 9 | lib/Target/RISCV/RISCVISelLowering.h | 1 + 10 | 2 files changed, 15 insertions(+) 11 | 12 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 13 | index c60b4abc2c8..adf0d0c70ab 100644 14 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | @@ -201,6 +201,20 @@ bool RISCVTargetLowering::isTruncateFree(EVT SrcVT, EVT DstVT) const { 17 | return (SrcBits == 64 && DestBits == 32); 18 | } 19 | 20 | +bool RISCVTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { 21 | + // Zexts are free if they can be combined with a load. 22 | + if (auto *LD = dyn_cast(Val)) { 23 | + EVT MemVT = LD->getMemoryVT(); 24 | + if ((MemVT == MVT::i8 || MemVT == MVT::i16 || 25 | + (Subtarget.is64Bit() && MemVT == MVT::i32)) && 26 | + (LD->getExtensionType() == ISD::NON_EXTLOAD || 27 | + LD->getExtensionType() == ISD::ZEXTLOAD)) 28 | + return true; 29 | + } 30 | + 31 | + return TargetLowering::isZExtFree(Val, VT2); 32 | +} 33 | + 34 | // Changes the condition code and swaps operands if necessary, so the SetCC 35 | // operation matches one of the comparisons supported directly in the RISC-V 36 | // ISA. 37 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 38 | index d6dfbf6625e..ccce434f69f 100644 39 | --- a/lib/Target/RISCV/RISCVISelLowering.h 40 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 41 | @@ -44,6 +44,7 @@ public: 42 | bool isLegalAddImmediate(int64_t Imm) const override; 43 | bool isTruncateFree(Type *SrcTy, Type *DstTy) const override; 44 | bool isTruncateFree(EVT SrcVT, EVT DstVT) const override; 45 | + bool isZExtFree(SDValue Val, EVT VT2) const override; 46 | 47 | // Provide custom lowering hooks for some operations. 48 | SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; 49 | -- 50 | 2.16.2 51 | 52 | -------------------------------------------------------------------------------- /0045-LegalizeDAG-promote-frameaddr-returnaddr-arguments-t.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [LegalizeDAG] promote frameaddr/returnaddr arguments to native 4 | integer width 5 | 6 | --- 7 | lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 9 +++++++++ 8 | lib/CodeGen/SelectionDAG/LegalizeTypes.h | 1 + 9 | 2 files changed, 10 insertions(+) 10 | 11 | diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 12 | index d9364ed9050..0aa1b58cbf8 100644 13 | --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 14 | +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 15 | @@ -955,6 +955,9 @@ bool DAGTypeLegalizer::PromoteIntegerOperand(SDNode *N, unsigned OpNo) { 16 | 17 | case ISD::ADDCARRY: 18 | case ISD::SUBCARRY: Res = PromoteIntOp_ADDSUBCARRY(N, OpNo); break; 19 | + 20 | + case ISD::FRAMEADDR: 21 | + case ISD::RETURNADDR: Res = PromoteIntOp_RETURNADDR(N, OpNo); break; 22 | } 23 | 24 | // If the result is null, the sub-method took care of registering results etc. 25 | @@ -1337,6 +1340,12 @@ SDValue DAGTypeLegalizer::PromoteIntOp_ADDSUBCARRY(SDNode *N, unsigned OpNo) { 26 | return SDValue(DAG.UpdateNodeOperands(N, LHS, RHS, Carry), 0); 27 | } 28 | 29 | +SDValue DAGTypeLegalizer::PromoteIntOp_RETURNADDR(SDNode *N, unsigned OpNo) { 30 | + // Promote the RETURNADDR/FRAMEADDR argument to a supported integer width. 31 | + SDValue Op = GetPromotedInteger(N->getOperand(0)); 32 | + return SDValue(DAG.UpdateNodeOperands(N, Op), 0); 33 | +} 34 | + 35 | //===----------------------------------------------------------------------===// 36 | // Integer Result Expansion 37 | //===----------------------------------------------------------------------===// 38 | diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h 39 | index 64cb80e0d85..fca50dc6f53 100644 40 | --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h 41 | +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h 42 | @@ -310,6 +310,7 @@ private: 43 | SDValue PromoteIntOp_MSCATTER(MaskedScatterSDNode *N, unsigned OpNo); 44 | SDValue PromoteIntOp_MGATHER(MaskedGatherSDNode *N, unsigned OpNo); 45 | SDValue PromoteIntOp_ADDSUBCARRY(SDNode *N, unsigned OpNo); 46 | + SDValue PromoteIntOp_RETURNADDR(SDNode *N, unsigned OpNo); 47 | 48 | void PromoteSetCCOperands(SDValue &LHS,SDValue &RHS, ISD::CondCode Code); 49 | 50 | -- 51 | 2.16.2 52 | 53 | -------------------------------------------------------------------------------- /0085-RISCV-Set-AllowRegisterRenaming-1.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Set AllowRegisterRenaming=1 4 | 5 | TODO: backport this so it is introduced at the same time as codegen. 6 | --- 7 | lib/Target/RISCV/RISCV.td | 1 + 8 | test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll | 4 ++-- 9 | test/CodeGen/RISCV/calls.ll | 4 ++-- 10 | 3 files changed, 5 insertions(+), 4 deletions(-) 11 | 12 | diff --git a/lib/Target/RISCV/RISCV.td b/lib/Target/RISCV/RISCV.td 13 | index f431738c3d7..bb68ef9c8bc 100644 14 | --- a/lib/Target/RISCV/RISCV.td 15 | +++ b/lib/Target/RISCV/RISCV.td 16 | @@ -92,4 +92,5 @@ def RISCV : Target { 17 | let InstructionSet = RISCVInstrInfo; 18 | let AssemblyParsers = [RISCVAsmParser]; 19 | let AssemblyWriters = [RISCVAsmWriter]; 20 | + let AllowRegisterRenaming = 1; 21 | } 22 | diff --git a/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll b/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll 23 | index 6ef034c48ee..1fbc429cae4 100644 24 | --- a/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll 25 | +++ b/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll 26 | @@ -278,7 +278,7 @@ define i64 @test_cttz_i64(i64 %a) nounwind { 27 | ; RV32I-NEXT: sw s8, 12(sp) 28 | ; RV32I-NEXT: mv s2, a1 29 | ; RV32I-NEXT: mv s3, a0 30 | -; RV32I-NEXT: addi a0, s3, -1 31 | +; RV32I-NEXT: addi a0, a0, -1 32 | ; RV32I-NEXT: not a1, s3 33 | ; RV32I-NEXT: and a0, a1, a0 34 | ; RV32I-NEXT: lui a1, 349525 35 | @@ -469,7 +469,7 @@ define i64 @test_cttz_i64_zero_undef(i64 %a) nounwind { 36 | ; RV32I-NEXT: sw s8, 12(sp) 37 | ; RV32I-NEXT: mv s2, a1 38 | ; RV32I-NEXT: mv s3, a0 39 | -; RV32I-NEXT: addi a0, s3, -1 40 | +; RV32I-NEXT: addi a0, a0, -1 41 | ; RV32I-NEXT: not a1, s3 42 | ; RV32I-NEXT: and a0, a1, a0 43 | ; RV32I-NEXT: lui a1, 349525 44 | diff --git a/test/CodeGen/RISCV/calls.ll b/test/CodeGen/RISCV/calls.ll 45 | index 5f71bdad961..8875015e5b3 100644 46 | --- a/test/CodeGen/RISCV/calls.ll 47 | +++ b/test/CodeGen/RISCV/calls.ll 48 | @@ -99,8 +99,8 @@ define i32 @test_call_external_many_args(i32 %a) nounwind { 49 | ; RV32I-NEXT: sw ra, 12(sp) 50 | ; RV32I-NEXT: sw s1, 8(sp) 51 | ; RV32I-NEXT: mv s1, a0 52 | -; RV32I-NEXT: sw s1, 4(sp) 53 | -; RV32I-NEXT: sw s1, 0(sp) 54 | +; RV32I-NEXT: sw a0, 4(sp) 55 | +; RV32I-NEXT: sw a0, 0(sp) 56 | ; RV32I-NEXT: lui a0, %hi(external_many_args) 57 | ; RV32I-NEXT: addi t0, a0, %lo(external_many_args) 58 | ; RV32I-NEXT: mv a0, s1 59 | -- 60 | 2.16.2 61 | 62 | -------------------------------------------------------------------------------- /docs/09-codegen-branches-and-function-calls.mkd: -------------------------------------------------------------------------------- 1 | # Codegen for branches and function calls 2 | 3 | ## Lowering branches 4 | 5 | Reviewing `include/llvm/CodeGen/ISDOpcodes.h` you can see that there are two 6 | representations of conditional branches. `BRCOND` has condition and target 7 | operands, while `BR_CC` is a compare+branch taking a condition code, the nodes 8 | to compare, and the block to branch to if the condition is true. Although 9 | `BR_CC` is a closer match to the RISC-V compare+branch instructions, the 10 | `BRCOND` form is easier to write tablegen patterns to match. Therefore, 11 | request that `BR_CC` be expanded: 12 | 13 | setOperationAction(ISD::BR_CC, XLenVT, Expand); 14 | 15 | And define patterns such as: 16 | 17 | // Match `(brcond (CondOp ..), ..)` and lower to the appropriate RISC-V branch 18 | // instruction. 19 | class BccPat 20 | : Pat<(brcond (i32 (CondOp GPR:$rs1, GPR:$rs2)), bb:$imm12), 21 | (Inst GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12)>; 22 | 23 | def : BccPat; 24 | 25 | A number of `setcc` condition codes don't have directly matching RISC-V 26 | instructions but can be supported by swapping the input operands: 27 | 28 | class BccSwapPat 29 | : Pat<(brcond (i32 (CondOp GPR:$rs1, GPR:$rs2)), bb:$imm12), 30 | (InstBcc GPR:$rs2, GPR:$rs1, bb:$imm12)>; 31 | 32 | // Condition codes that don't have matching RISC-V branch instructions, but 33 | // are trivially supported by swapping the two input operands 34 | def : BccSwapPat; 35 | def : BccSwapPat; 36 | def : BccSwapPat; 37 | def : BccSwapPat; 38 | 39 | In order for the branch test function to work, 40 | `RISCVInstrInfo::storeRegToStackSlot` and 41 | `RISCVInstrInfo::loadRegFromStackSlot` must be implemented, as they are 42 | required for the generated register spills. These functions simply require 43 | generating an appropriate load or store. 44 | 45 | ## Codegen for functioncalls 46 | 47 | Define a pseudo-instruction for call which expands to `JALR`: 48 | 49 | let isCall = 1, Defs=[X1] in 50 | def PseudoCALL : Pseudo<(outs), (ins GPR:$rs1), [(Call GPR:$rs1)]>, 51 | PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>; 52 | 53 | The major missing component which needs to be implemented is 54 | `RISCVTargetLowering::LowerCall`. This is responsible for lowering a call to 55 | the appropriate SelectionDAG nodes: `call_start`, `CALL`, and `callseq_end`. 56 | It is responsible for copying the arguments and copying the result. 57 | 58 | 59 | -------------------------------------------------------------------------------- /0046-LegalizeDAG-promote-PREFETCH-operands-to-native-inte.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [LegalizeDAG] promote PREFETCH operands to native integer width 4 | 5 | --- 6 | lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 14 ++++++++++++++ 7 | lib/CodeGen/SelectionDAG/LegalizeTypes.h | 1 + 8 | 2 files changed, 15 insertions(+) 9 | 10 | diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 11 | index 0aa1b58cbf8..c90842db604 100644 12 | --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 13 | +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp 14 | @@ -958,6 +958,9 @@ bool DAGTypeLegalizer::PromoteIntegerOperand(SDNode *N, unsigned OpNo) { 15 | 16 | case ISD::FRAMEADDR: 17 | case ISD::RETURNADDR: Res = PromoteIntOp_RETURNADDR(N, OpNo); break; 18 | + case ISD::PREFETCH: 19 | + Res = PromoteIntOp_PREFETCH(N, OpNo); 20 | + break; 21 | } 22 | 23 | // If the result is null, the sub-method took care of registering results etc. 24 | @@ -1346,6 +1349,17 @@ SDValue DAGTypeLegalizer::PromoteIntOp_RETURNADDR(SDNode *N, unsigned OpNo) { 25 | return SDValue(DAG.UpdateNodeOperands(N, Op), 0); 26 | } 27 | 28 | +SDValue DAGTypeLegalizer::PromoteIntOp_PREFETCH(SDNode *N, unsigned OpNo) { 29 | + // Promote the rw, locality, and cache type arguments to a supported integer 30 | + // width. 31 | + SDValue Op2 = GetPromotedInteger(N->getOperand(2)); 32 | + SDValue Op3 = GetPromotedInteger(N->getOperand(3)); 33 | + SDValue Op4 = GetPromotedInteger(N->getOperand(4)); 34 | + return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1), 35 | + Op2, Op3, Op4), 36 | + 0); 37 | +} 38 | + 39 | //===----------------------------------------------------------------------===// 40 | // Integer Result Expansion 41 | //===----------------------------------------------------------------------===// 42 | diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h 43 | index fca50dc6f53..5c2a5c4dddb 100644 44 | --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h 45 | +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h 46 | @@ -311,6 +311,7 @@ private: 47 | SDValue PromoteIntOp_MGATHER(MaskedGatherSDNode *N, unsigned OpNo); 48 | SDValue PromoteIntOp_ADDSUBCARRY(SDNode *N, unsigned OpNo); 49 | SDValue PromoteIntOp_RETURNADDR(SDNode *N, unsigned OpNo); 50 | + SDValue PromoteIntOp_PREFETCH(SDNode *N, unsigned OpNo); 51 | 52 | void PromoteSetCCOperands(SDValue &LHS,SDValue &RHS, ISD::CondCode Code); 53 | 54 | -- 55 | 2.16.2 56 | 57 | -------------------------------------------------------------------------------- /0077-RISCV-Implement-computeKnownBitsForTargetNode-for-RI.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement computeKnownBitsForTargetNode for 4 | RISCVISD::SELECT_CC 5 | 6 | Doesn't seem to have any real impact on the code I'm testing against. 7 | --- 8 | lib/Target/RISCV/RISCVISelLowering.cpp | 14 ++++++++++++++ 9 | lib/Target/RISCV/RISCVISelLowering.h | 5 +++++ 10 | 2 files changed, 19 insertions(+) 11 | 12 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 13 | index adf0d0c70ab..bac74ee62c5 100644 14 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | @@ -30,6 +30,7 @@ 17 | #include "llvm/IR/DiagnosticPrinter.h" 18 | #include "llvm/Support/Debug.h" 19 | #include "llvm/Support/ErrorHandling.h" 20 | +#include "llvm/Support/KnownBits.h" 21 | #include "llvm/Support/raw_ostream.h" 22 | 23 | using namespace llvm; 24 | @@ -215,6 +216,19 @@ bool RISCVTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { 25 | return TargetLowering::isZExtFree(Val, VT2); 26 | } 27 | 28 | +void RISCVTargetLowering::computeKnownBitsForTargetNode( 29 | + const SDValue Op, KnownBits &Known, const APInt &DemandedElts, 30 | + const SelectionDAG &DAG, unsigned Depth) const { 31 | + if (Op.getOpcode() != RISCVISD::SELECT_CC) 32 | + return; 33 | + 34 | + KnownBits Known2; 35 | + DAG.computeKnownBits(Op->getOperand(3), Known, Depth + 1); 36 | + DAG.computeKnownBits(Op->getOperand(4), Known2, Depth + 1); 37 | + Known.Zero &= Known2.Zero; 38 | + Known.One &= Known2.One; 39 | +} 40 | + 41 | // Changes the condition code and swaps operands if necessary, so the SetCC 42 | // operation matches one of the comparisons supported directly in the RISC-V 43 | // ISA. 44 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 45 | index ccce434f69f..807cb9c0b8d 100644 46 | --- a/lib/Target/RISCV/RISCVISelLowering.h 47 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 48 | @@ -46,6 +46,11 @@ public: 49 | bool isTruncateFree(EVT SrcVT, EVT DstVT) const override; 50 | bool isZExtFree(SDValue Val, EVT VT2) const override; 51 | 52 | + void computeKnownBitsForTargetNode(const SDValue Op, KnownBits &Known, 53 | + const APInt &DemandedElts, 54 | + const SelectionDAG &DAG, 55 | + unsigned Depth = 0) const override; 56 | + 57 | // Provide custom lowering hooks for some operations. 58 | SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; 59 | 60 | -- 61 | 2.16.2 62 | 63 | -------------------------------------------------------------------------------- /0072-RISCV-Implement-isLegalAddressingMode-for-RISC-V.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement isLegalAddressingMode for RISC-V 4 | 5 | Doesn't change codegen at all for my small benchmark set, very minor changes 6 | across the gcc torture suite (not always positive). Despite that, presenting 7 | correct information to LLVM seems the right thing to do. 8 | 9 | TODO: test that captures codegen change. 10 | --- 11 | lib/Target/RISCV/RISCVISelLowering.cpp | 24 ++++++++++++++++++++++++ 12 | lib/Target/RISCV/RISCVISelLowering.h | 4 ++++ 13 | 2 files changed, 28 insertions(+) 14 | 15 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | index bc388ea3be6..e9c003aeba9 100644 17 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 18 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 19 | @@ -149,6 +149,30 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, 20 | setMinimumJumpTableEntries(INT_MAX); 21 | } 22 | 23 | +bool RISCVTargetLowering::isLegalAddressingMode(const DataLayout &DL, 24 | + const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I) const { 25 | + // No global is ever allowed as a base. 26 | + if (AM.BaseGV) 27 | + return false; 28 | + 29 | + // Require a 12-bit signed offset. 30 | + if (!isInt<12>(AM.BaseOffs)) 31 | + return false; 32 | + 33 | + switch (AM.Scale) { 34 | + case 0: // "r+i" or just "i", depending on HasBaseReg. 35 | + break; 36 | + case 1: 37 | + if (!AM.HasBaseReg) // allow "r+i". 38 | + break; 39 | + return false; // disallow "r+r" or "r+r+i". 40 | + default: 41 | + return false; 42 | + } 43 | + 44 | + return true; 45 | +} 46 | + 47 | // Changes the condition code and swaps operands if necessary, so the SetCC 48 | // operation matches one of the comparisons supported directly in the RISC-V 49 | // ISA. 50 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 51 | index 30403f45045..e7dd46fc835 100644 52 | --- a/lib/Target/RISCV/RISCVISelLowering.h 53 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 54 | @@ -37,6 +37,10 @@ public: 55 | explicit RISCVTargetLowering(const TargetMachine &TM, 56 | const RISCVSubtarget &STI); 57 | 58 | + bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, 59 | + unsigned AS, 60 | + Instruction *I = nullptr) const override; 61 | + 62 | // Provide custom lowering hooks for some operations. 63 | SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; 64 | 65 | -- 66 | 2.16.2 67 | 68 | -------------------------------------------------------------------------------- /0075-RISCV-Implement-isTruncateFree.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement isTruncateFree 4 | 5 | Adapted from ARM's implementation introduced in r313533 and r314280. Actually 6 | triggers quite a few codegen differences in the torture suite. 7 | --- 8 | lib/Target/RISCV/RISCVISelLowering.cpp | 20 ++++++++++++++++++++ 9 | lib/Target/RISCV/RISCVISelLowering.h | 2 ++ 10 | 2 files changed, 22 insertions(+) 11 | 12 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 13 | index a9f9f5c7d56..c60b4abc2c8 100644 14 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | @@ -181,6 +181,26 @@ bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm) const { 17 | return isInt<12>(Imm); 18 | } 19 | 20 | +// On RV32, 64-bit integers are split into their high and low parts and held 21 | +// in two different registers, so the trunc is free since the low register can 22 | +// just be used. 23 | +bool RISCVTargetLowering::isTruncateFree(Type *SrcTy, Type *DstTy) const { 24 | + if (Subtarget.is64Bit() || !SrcTy->isIntegerTy() || !DstTy->isIntegerTy()) 25 | + return false; 26 | + unsigned SrcBits = SrcTy->getPrimitiveSizeInBits(); 27 | + unsigned DestBits = DstTy->getPrimitiveSizeInBits(); 28 | + return (SrcBits == 64 && DestBits == 32); 29 | +} 30 | + 31 | +bool RISCVTargetLowering::isTruncateFree(EVT SrcVT, EVT DstVT) const { 32 | + if (Subtarget.is64Bit() || SrcVT.isVector() || DstVT.isVector() || 33 | + !SrcVT.isInteger() || !DstVT.isInteger()) 34 | + return false; 35 | + unsigned SrcBits = SrcVT.getSizeInBits(); 36 | + unsigned DestBits = DstVT.getSizeInBits(); 37 | + return (SrcBits == 64 && DestBits == 32); 38 | +} 39 | + 40 | // Changes the condition code and swaps operands if necessary, so the SetCC 41 | // operation matches one of the comparisons supported directly in the RISC-V 42 | // ISA. 43 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 44 | index 17183004df6..d6dfbf6625e 100644 45 | --- a/lib/Target/RISCV/RISCVISelLowering.h 46 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 47 | @@ -42,6 +42,8 @@ public: 48 | Instruction *I = nullptr) const override; 49 | bool isLegalICmpImmediate(int64_t Imm) const override; 50 | bool isLegalAddImmediate(int64_t Imm) const override; 51 | + bool isTruncateFree(Type *SrcTy, Type *DstTy) const override; 52 | + bool isTruncateFree(EVT SrcVT, EVT DstVT) const override; 53 | 54 | // Provide custom lowering hooks for some operations. 55 | SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; 56 | -- 57 | 2.16.2 58 | 59 | -------------------------------------------------------------------------------- /0071-RISCV-Expose-options-to-enable-optimisation-of-compl.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Expose options to enable optimisation of complex GEPs 4 | 5 | Experimental, it seems both PPC and AArch64 have experimented with this. Seems 6 | to have minimal effect on generated code in my current benchmark set. 7 | --- 8 | lib/Target/RISCV/LLVMBuild.txt | 2 +- 9 | lib/Target/RISCV/RISCVTargetMachine.cpp | 20 ++++++++++++++++++++ 10 | 2 files changed, 21 insertions(+), 1 deletion(-) 11 | 12 | diff --git a/lib/Target/RISCV/LLVMBuild.txt b/lib/Target/RISCV/LLVMBuild.txt 13 | index ab21565b0c2..840f3a47f22 100644 14 | --- a/lib/Target/RISCV/LLVMBuild.txt 15 | +++ b/lib/Target/RISCV/LLVMBuild.txt 16 | @@ -31,5 +31,5 @@ type = Library 17 | name = RISCVCodeGen 18 | parent = RISCV 19 | required_libraries = AsmPrinter Core CodeGen MC RISCVAsmPrinter RISCVDesc 20 | - RISCVInfo SelectionDAG Support Target 21 | + RISCVInfo Scalar SelectionDAG Support Target 22 | add_to_library_groups = RISCV 23 | diff --git a/lib/Target/RISCV/RISCVTargetMachine.cpp b/lib/Target/RISCV/RISCVTargetMachine.cpp 24 | index 7cf90fa66e2..8b2adaeac3b 100644 25 | --- a/lib/Target/RISCV/RISCVTargetMachine.cpp 26 | +++ b/lib/Target/RISCV/RISCVTargetMachine.cpp 27 | @@ -21,8 +21,15 @@ 28 | #include "llvm/Support/FormattedStream.h" 29 | #include "llvm/Support/TargetRegistry.h" 30 | #include "llvm/Target/TargetOptions.h" 31 | +#include "llvm/Transforms/Scalar.h" 32 | + 33 | using namespace llvm; 34 | 35 | +static cl::opt 36 | +EnableGEPOpt("riscv-gep-opt", cl::Hidden, 37 | + cl::desc("Enable optimizations on complex GEPs"), 38 | + cl::init(false)); 39 | + 40 | extern "C" void LLVMInitializeRISCVTarget() { 41 | RegisterTargetMachine X(getTheRISCV32Target()); 42 | RegisterTargetMachine Y(getTheRISCV64Target()); 43 | @@ -87,6 +94,19 @@ TargetPassConfig *RISCVTargetMachine::createPassConfig(PassManagerBase &PM) { 44 | void RISCVPassConfig::addIRPasses() { 45 | addPass(createAtomicExpandPass()); 46 | 47 | + if (TM->getOptLevel() == CodeGenOpt::Aggressive && EnableGEPOpt) { 48 | + // Call SeparateConstOffsetFromGEP pass to extract constants within indices 49 | + // and lower a GEP with multiple indices to either arithmetic operations or 50 | + // multiple GEPs with single index. 51 | + addPass(createSeparateConstOffsetFromGEPPass(TM, true)); 52 | + // Call EarlyCSE pass to find and remove subexpressions in the lowered 53 | + // result. 54 | + addPass(createEarlyCSEPass()); 55 | + // Do loop invariant code motion in case part of the lowered result is 56 | + // invariant. 57 | + addPass(createLICMPass()); 58 | + } 59 | + 60 | TargetPassConfig::addIRPasses(); 61 | } 62 | 63 | -- 64 | 2.16.2 65 | 66 | -------------------------------------------------------------------------------- /0038-RISCV-MC-layer-support-for-the-standard-RV64M-instru.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] MC layer support for the standard RV64M instruction set 4 | extension 5 | 6 | --- 7 | lib/Target/RISCV/RISCVInstrInfoM.td | 8 ++++++++ 8 | test/MC/RISCV/rv32m-invalid.s | 9 +++++++++ 9 | test/MC/RISCV/rv64m-valid.s | 20 ++++++++++++++++++++ 10 | 3 files changed, 37 insertions(+) 11 | create mode 100644 test/MC/RISCV/rv32m-invalid.s 12 | create mode 100644 test/MC/RISCV/rv64m-valid.s 13 | 14 | diff --git a/lib/Target/RISCV/RISCVInstrInfoM.td b/lib/Target/RISCV/RISCVInstrInfoM.td 15 | index a253c1eb811..fec9c1f9399 100644 16 | --- a/lib/Target/RISCV/RISCVInstrInfoM.td 17 | +++ b/lib/Target/RISCV/RISCVInstrInfoM.td 18 | @@ -26,3 +26,11 @@ def DIVU : ALU_rr<0b0000001, 0b101, "divu">; 19 | def REM : ALU_rr<0b0000001, 0b110, "rem">; 20 | def REMU : ALU_rr<0b0000001, 0b111, "remu">; 21 | } // Predicates = [HasStdExtM] 22 | + 23 | +let Predicates = [HasStdExtM, IsRV64] in { 24 | +def MULW : ALUW_rr<0b0000001, 0b000, "mulw">; 25 | +def DIVW : ALUW_rr<0b0000001, 0b100, "divw">; 26 | +def DIVUW : ALUW_rr<0b0000001, 0b101, "divuw">; 27 | +def REMW : ALUW_rr<0b0000001, 0b110, "remw">; 28 | +def REMUW : ALUW_rr<0b0000001, 0b111, "remuw">; 29 | +} // Predicates = [HasStdExtM, IsRV64] 30 | diff --git a/test/MC/RISCV/rv32m-invalid.s b/test/MC/RISCV/rv32m-invalid.s 31 | new file mode 100644 32 | index 00000000000..5e268e8b916 33 | --- /dev/null 34 | +++ b/test/MC/RISCV/rv32m-invalid.s 35 | @@ -0,0 +1,9 @@ 36 | +# RUN: not llvm-mc -triple riscv32 -mattr=+m < %s 2>&1 | FileCheck %s 37 | + 38 | +# RV64M instructions can't be used for RV32 39 | +mulw ra, sp, gp # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled 40 | +divw tp, t0, t1 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled 41 | +divuw t2, s0, s2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled 42 | +remw a0, a1, a2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled 43 | +remuw a3, a4, a5 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled 44 | + 45 | diff --git a/test/MC/RISCV/rv64m-valid.s b/test/MC/RISCV/rv64m-valid.s 46 | new file mode 100644 47 | index 00000000000..3de540dac21 48 | --- /dev/null 49 | +++ b/test/MC/RISCV/rv64m-valid.s 50 | @@ -0,0 +1,20 @@ 51 | +# RUN: llvm-mc %s -triple=riscv64 -mattr=+m -show-encoding \ 52 | +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 53 | +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+m < %s \ 54 | +# RUN: | llvm-objdump -mattr=+m -d - | FileCheck -check-prefix=CHECK-INST %s 55 | + 56 | +# CHECK-INST: mulw ra, sp, gp 57 | +# CHECK: encoding: [0xbb,0x00,0x31,0x02] 58 | +mulw ra, sp, gp 59 | +# CHECK-INST: divw tp, t0, t1 60 | +# CHECK: encoding: [0x3b,0xc2,0x62,0x02] 61 | +divw tp, t0, t1 62 | +# CHECK-INST: divuw t2, s0, s2 63 | +# CHECK: encoding: [0xbb,0x53,0x24,0x03] 64 | +divuw t2, s0, s2 65 | +# CHECK-INST: remw a0, a1, a2 66 | +# CHECK: encoding: [0x3b,0xe5,0xc5,0x02] 67 | +remw a0, a1, a2 68 | +# CHECK-INST: remuw a3, a4, a5 69 | +# CHECK: encoding: [0xbb,0x76,0xf7,0x02] 70 | +remuw a3, a4, a5 71 | -- 72 | 2.16.2 73 | 74 | -------------------------------------------------------------------------------- /docs/06-relocations-and-fixups.mkd: -------------------------------------------------------------------------------- 1 | # Implementing support for relocations and fixups 2 | 3 | A relocation is emitted when there is an unresolved symbol reference (for 4 | instance, a reference to a function in another compilation unit). In LLVM, a 5 | "fixup" is generated when an unknown piece of information is referenced (e.g. 6 | an unresolved symbol reference). Some fixups can be resolved before the ELF is 7 | generated, while others must be converted to relocations. Every relocation was 8 | once a fixup, but not every fixup becomes a relocation. 9 | 10 | Once implementation of this is completed, the MC layer will be implemented and 11 | you'll be ready to move on to code generation. 12 | 13 | ## Introducing fixups 14 | 15 | First, introduce `RISCVFixupKinds.h` and implement 16 | `RISCVAsmBackend::getFixupKindInfo`. This defines the supported fixups, and 17 | metadata about each fixup (offset in an instruction, the length, whether it's 18 | relative to the program counter). Next, implement 19 | `RISCVAsmBackend::applyFixup`. If the fixup value is known at the time 20 | `applyFixup` is called, this method is responsible for modifying the encoded 21 | instruction. It's useful to introduce a helper function, e.g. 22 | `adjustFixupValue` which will modify the value as necessary. This is necessary 23 | to manipulate values so the bit layout matches that needed for the target 24 | RISC-V instruction. 25 | 26 | With that logic in place, the next steps are to 1) implement support for 27 | generating fixups from the assembly parser and 2) implement support for 28 | generating relocations when fixups are left unresolved. 29 | 30 | ## Changes to the assembler 31 | 32 | Generating fixups from the assembly parser requires the implementation of 33 | `RISCVMCExpr`. Instances of this will be created to allow the assembly parser 34 | to record operands with modifiers like `%pcrel_hi()`. `RISCVMCExpr` introduces 35 | yet another concept - `VariantKind`s. These are needed to represent cases 36 | where operand modifiers don't result in fixups, for instance `%lo()` might be 37 | applied to a constant value. 38 | 39 | RISCVAsmParser must be modified so that symbols can be parsed, and so it must 40 | be able to tolerate when instruction operands. Additionally, it must 41 | successfully parse operand modifiers. As is usual with the LLVM assembly 42 | parser, it will recognise any modifier with the correct form, and then later 43 | validate if the operand modifier was valid for RISC-V or not. 44 | 45 | When converting from a VariantKind to a fixup, there's a question of how to 46 | convert `RISCVMCExpr::VK_RISCV_LO`, given that there are two different 47 | encodings of 12-bit immediates amongst the RISC-V instruction formats 48 | (I-format and S-format instructions distribute the immediate bits 49 | differently). Although this could be handled by hard-coding a list of I-type 50 | opcodes and a list of S-type opcodes, it would be preferable to avoid this 51 | sort of hard-coding. By adding the instruction format as a property of each 52 | instruction, you can select the appropriate fixup by checking the format of 53 | the current instruction. 54 | 55 | ## Relocations 56 | 57 | Finally, you can modify `RISCVELFObjectWriter::getRelocType` to map a fixup 58 | type to the appropriate relocation type. 59 | -------------------------------------------------------------------------------- /0078-RISCV-Implement-isLoadFromStackSlot-and-isStoreToSta.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement isLoadFromStackSlot and isStoreToStackSlot 4 | 5 | This does result in some codegen changes to the torture suite. 6 | --- 7 | lib/Target/RISCV/RISCVInstrInfo.cpp | 49 +++++++++++++++++++++++++++++++++++++ 8 | lib/Target/RISCV/RISCVInstrInfo.h | 5 ++++ 9 | 2 files changed, 54 insertions(+) 10 | 11 | diff --git a/lib/Target/RISCV/RISCVInstrInfo.cpp b/lib/Target/RISCV/RISCVInstrInfo.cpp 12 | index 7f557f2ab87..f99fbf5576c 100644 13 | --- a/lib/Target/RISCV/RISCVInstrInfo.cpp 14 | +++ b/lib/Target/RISCV/RISCVInstrInfo.cpp 15 | @@ -33,6 +33,55 @@ RISCVInstrInfo::RISCVInstrInfo(const RISCVSubtarget &Subtarget) 16 | : RISCVGenInstrInfo(RISCV::ADJCALLSTACKDOWN, RISCV::ADJCALLSTACKUP), 17 | Subtarget(Subtarget) {} 18 | 19 | +unsigned RISCVInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, 20 | + int &FrameIndex) const { 21 | + switch (MI.getOpcode()) { 22 | + default: 23 | + return 0; 24 | + case RISCV::LB: 25 | + case RISCV::LBU: 26 | + case RISCV::LH: 27 | + case RISCV::LHU: 28 | + case RISCV::LW: 29 | + case RISCV::FLW: 30 | + case RISCV::LWU: 31 | + case RISCV::LD: 32 | + case RISCV::FLD: 33 | + break; 34 | + } 35 | + 36 | + if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() && 37 | + MI.getOperand(2).getImm() == 0) { 38 | + FrameIndex = MI.getOperand(1).getIndex(); 39 | + return MI.getOperand(0).getReg(); 40 | + } 41 | + 42 | + return 0; 43 | +} 44 | + 45 | +unsigned RISCVInstrInfo::isStoreToStackSlot(const MachineInstr &MI, 46 | + int &FrameIndex) const { 47 | + switch (MI.getOpcode()) { 48 | + default: 49 | + return 0; 50 | + case RISCV::SB: 51 | + case RISCV::SH: 52 | + case RISCV::SW: 53 | + case RISCV::FSW: 54 | + case RISCV::SD: 55 | + case RISCV::FSD: 56 | + break; 57 | + } 58 | + 59 | + if (MI.getOperand(0).isFI() && MI.getOperand(1).isImm() && 60 | + MI.getOperand(1).getImm() == 0) { 61 | + FrameIndex = MI.getOperand(0).getIndex(); 62 | + return MI.getOperand(2).getReg(); 63 | + } 64 | + 65 | + return 0; 66 | +} 67 | + 68 | void RISCVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 69 | MachineBasicBlock::iterator MBBI, 70 | const DebugLoc &DL, unsigned DstReg, 71 | diff --git a/lib/Target/RISCV/RISCVInstrInfo.h b/lib/Target/RISCV/RISCVInstrInfo.h 72 | index c7c91b64099..d9b7ea55e77 100644 73 | --- a/lib/Target/RISCV/RISCVInstrInfo.h 74 | +++ b/lib/Target/RISCV/RISCVInstrInfo.h 75 | @@ -30,6 +30,11 @@ class RISCVInstrInfo : public RISCVGenInstrInfo { 76 | public: 77 | explicit RISCVInstrInfo(const RISCVSubtarget &Subtarget); 78 | 79 | + unsigned isLoadFromStackSlot(const MachineInstr &MI, 80 | + int &FrameIndex) const override; 81 | + unsigned isStoreToStackSlot(const MachineInstr &MI, 82 | + int &FrameIndex) const override; 83 | + 84 | void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 85 | const DebugLoc &DL, unsigned DstReg, unsigned SrcReg, 86 | bool KillSrc) const override; 87 | -- 88 | 2.16.2 89 | 90 | -------------------------------------------------------------------------------- /docs/04-instruction-printer-and-testing.mkd: -------------------------------------------------------------------------------- 1 | # Implementing instruction printing and testing 2 | 3 | With the bulk of the necessary infrastructure in place, you're now in a 4 | position to add the final piece needed to test the assembler. 5 | 6 | ## Adding an instruction printer 7 | 8 | RISCVInstPrinter is needed to convert an `MCInst` to a string. With this class 9 | implemented, the `-show-encoding` option of `llvm-mc` can be used to check 10 | that the way parsed instructions are printed matches expectations, and that 11 | the encoding is correct. 12 | 13 | As with much of the MC layer, the majority of the "work" is done by code 14 | generated using TableGen. 15 | 16 | void RISCVInstPrinter::printInst(const MCInst *MI, raw_ostream &O, 17 | StringRef Annot, const MCSubtargetInfo &ST 18 | printInstruction(MI, O); 19 | printAnnotation(O, Annot); 20 | } 21 | 22 | void RISCVInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const { 23 | O << getRegisterName(RegNo); 24 | } 25 | 26 | void RISCVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, 27 | raw_ostream &O, const char *Modifier) { 28 | assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); 29 | const MCOperand &MO = MI->getOperand(OpNo); 30 | 31 | if (MO.isReg()) { 32 | printRegName(O, MO.getReg()); 33 | return; 34 | } 35 | 36 | if (MO.isImm()) { 37 | O << MO.getImm(); 38 | return; 39 | } 40 | 41 | assert(MO.isExpr() && "Unknown operand kind in printOperand"); 42 | MO.getExpr()->print(O, &MAI); 43 | } 44 | 45 | ## Implementing tests 46 | 47 | After creating the `test/MC/RISCV` directory, you must create a `lit.local.cfg` 48 | file containing: 49 | 50 | if not 'RISCV' in config.root.targets: 51 | config.unsupported = True 52 | 53 | This ensures that the tests are only run when LLVM is built with RISCV support. 54 | 55 | LLVM tests typically make use of the 56 | [FileCheck](http://llvm.org/docs/CommandGuide/FileCheck.html) utility to check 57 | for patterns in tool output. There's lots of flexibility for how to struct 58 | tests, but I suggest creating `rv32i-valid.s` to check that valid RISC-V 59 | instructions are assembled correctly, and `rv32i-invalid.s` to check 60 | diagnostics for invalid instructions. 61 | 62 | For instance, `rv32i-valid.s` may contain code like: 63 | 64 | # RUN: llvm-mc %s -triple=riscv32 -show-encoding \ 65 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 66 | # RUN: llvm-mc %s -triple=riscv64 -show-encoding \ 67 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 68 | 69 | # CHECK-INST: addi ra, sp, 2 70 | # CHECK: encoding: [0x93,0x00,0x21,0x00] 71 | addi ra, sp, 2 72 | # CHECK-INST: slti a0, a2, -20 73 | # CHECK: encoding: [0x13,0x25,0xc6,0xfe] 74 | slti a0, a2, -20 75 | 76 | While `rv32i-invalid.s` may contain code like: 77 | 78 | # RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s 79 | 80 | # Out of range immediates 81 | ori a0, a1, -2049 # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [-2048, 2047] 82 | andi ra, sp, 2048 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [-2048, 2047] 83 | 84 | ## Adding support for all instructions 85 | 86 | At this point, you can ensure that all RV32I instructions are defined in 87 | `RISCVInstrInfo.td`, and can be assembled correctly. 88 | -------------------------------------------------------------------------------- /docs/08-codegen-memory-operations.mkd: -------------------------------------------------------------------------------- 1 | # Codegen support for memory operations 2 | 3 | ## Prequisite: materializing constants 4 | 5 | This set of documentation lists each implementation task in the order it was 6 | needed. When writing an LLVM backend yourself, it's not always so obvious what 7 | the next step should be. Often you'll start trying to implement a new feature, 8 | and at that point discover pre-requisites. In this case, if you started to 9 | implement memory operations you'd quickly find test cases that require the 10 | ability to materialize constants (load a constant into a register). 11 | 12 | The good news is that implementing support for materialising constants is 13 | easy, and can be done just by modifying `RISCVInstrInfo.td`. Firstly, a 14 | pattern to match a signed 12-bit immediate: 15 | 16 | def : Pat<(simm12:$imm), (ADDI X0, simm12:$imm)>; 17 | 18 | This is straight forward - a 12-bit immediate is a valid operand to `ADDI`. 19 | For larger immediates, more work is required. You want to generate a 20 | combination of addi and lui, where addi takes the low 12 bits and lui takes 21 | the 20 bits. It's actually slightly more complex than that: as it's necessary 22 | to compensate for the fact the `ADDI` operand will be sign-extended. The 23 | pattern looks like this: 24 | 25 | def : Pat<(simm32:$imm), (ADDI (LUI (HI20 imm:$imm)), (LO12Sext imm:$imm))>; 26 | 27 | Where `HI20` and `LO12Sext` are transformations on the immediate to create the 28 | correct operand: 29 | 30 | // Extract least significant 12 bits from an immediate value and sign extend 31 | // them. 32 | def LO12Sext : SDNodeXFormgetTargetConstant(SignExtend64<12>(N->getZExtValue()), 34 | SDLoc(N), N->getValueType(0)); 35 | }]>; 36 | 37 | // Extract the most significant 20 bits from an immediate value. Add 1 if bit 38 | // 11 is 1, to compensate for the low 12 bits in the matching immediate addi 39 | // or ld/st being negative. 40 | def HI20 : SDNodeXFormgetTargetConstant(((N->getZExtValue()+0x800) >> 12) & 0xfffff, 42 | SDLoc(N), N->getValueType(0)); 43 | }]>; 44 | 45 | ## Codegen support for memory operations 46 | 47 | Two patterns are required for load and store to match the 1) a load/store of 48 | an address with no offset and 2) a load/store of an address with offset. The 49 | latter will be represented by a `SelectionDAG` subtree with an `add` node as 50 | the operand to the load/store. The following multiclass demonstrates this: 51 | 52 | multiclass LdPat { 53 | def : Pat<(LoadOp GPR:$rs1), (Inst GPR:$rs1, 0)>; 54 | def : Pat<(LoadOp (add GPR:$rs1, simm12:$imm12)), 55 | (Inst GPR:$rs1, simm12:$imm12)>; 56 | } 57 | 58 | RISC-V features sign-extending and zero-extending loads ('unsigned') data 59 | values smaller than word size. We must specify patterns for signext, zeroext, 60 | and anyext (don't care) loads. A test such as below covers these three cases: 61 | 62 | define i32 @lh(i16 *%a) nounwind { 63 | ; RV32I-LABEL: lh: 64 | ; RV32I: # %bb.0: 65 | ; RV32I-NEXT: lh a1, 0(a0) 66 | ; RV32I-NEXT: lh a0, 4(a0) 67 | ; RV32I-NEXT: jalr zero, ra, 0 68 | %1 = getelementptr i16, i16* %a, i32 2 69 | %2 = load i16, i16* %1 70 | %3 = sext i16 %2 to i32 71 | ; the unused load will produce an anyext for selection 72 | %4 = load volatile i16, i16* %a 73 | ret i32 %3 74 | } 75 | 76 | 77 | -------------------------------------------------------------------------------- /0053-RISCV-WIP-Codegen-support-for-RV32F-fused-multiply-a.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV][WIP] Codegen support for RV32F fused multiply-add operations 4 | 5 | --- 6 | lib/Target/RISCV/RISCVInstrInfoF.td | 10 +++++++ 7 | test/CodeGen/RISCV/float-fma.ll | 54 +++++++++++++++++++++++++++++++++++++ 8 | 2 files changed, 64 insertions(+) 9 | create mode 100644 test/CodeGen/RISCV/float-fma.ll 10 | 11 | diff --git a/lib/Target/RISCV/RISCVInstrInfoF.td b/lib/Target/RISCV/RISCVInstrInfoF.td 12 | index fa64775af00..8c2a8ace895 100644 13 | --- a/lib/Target/RISCV/RISCVInstrInfoF.td 14 | +++ b/lib/Target/RISCV/RISCVInstrInfoF.td 15 | @@ -239,6 +239,16 @@ def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), (FSGNJN_S $rs1, $rs2)>; 16 | def : PatFpr32Fpr32; 17 | def : PatFpr32Fpr32; 18 | 19 | +/// Fused multiply-add operations 20 | + 21 | +def : Pat<(fma FPR32:$rs1, FPR32:$rs2, FPR32:$rs3), 22 | + (FMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>; 23 | +// fmsub: rs1*rs2-rs3 24 | +def : Pat<(fma FPR32:$rs1, FPR32:$rs2, (fneg FPR32:$rs3)), 25 | + (FMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, 0b111)>; 26 | + 27 | +// TODO: other FMA patterns 28 | + 29 | /// Setcc 30 | 31 | def : PatFpr32Fpr32; 32 | diff --git a/test/CodeGen/RISCV/float-fma.ll b/test/CodeGen/RISCV/float-fma.ll 33 | new file mode 100644 34 | index 00000000000..ca6baba1530 35 | --- /dev/null 36 | +++ b/test/CodeGen/RISCV/float-fma.ll 37 | @@ -0,0 +1,54 @@ 38 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 39 | +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ 40 | +; RUN: | FileCheck -check-prefix=RV32IF %s 41 | + 42 | +declare float @llvm.fma.f32(float, float, float) 43 | + 44 | +define float @fmadd_s_fma_intrinsic(float %a, float %b, float %c) nounwind { 45 | +; RV32IF-LABEL: fmadd_s_fma_intrinsic: 46 | +; RV32IF: # %bb.0: 47 | +; RV32IF-NEXT: fmv.w.x ft0, a2 48 | +; RV32IF-NEXT: fmv.w.x ft1, a1 49 | +; RV32IF-NEXT: fmv.w.x ft2, a0 50 | +; RV32IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 51 | +; RV32IF-NEXT: fmv.x.w a0, ft0 52 | +; RV32IF-NEXT: jalr zero, ra, 0 53 | + %1 = call float @llvm.fma.f32(float %a, float %b, float %c) 54 | + ret float %1 55 | +} 56 | + 57 | +declare float @llvm.fmuladd.f32(float, float, float) 58 | + 59 | +define float @fmadd_s_fmuladd_intrinsic(float %a, float %b, float %c) nounwind { 60 | +; Use of fmadd depends on TargetLowering::isFMAFasterthanFMulAndFAdd 61 | +; RV32IF-LABEL: fmadd_s_fmuladd_intrinsic: 62 | +; RV32IF: # %bb.0: 63 | +; RV32IF-NEXT: fmv.w.x ft0, a1 64 | +; RV32IF-NEXT: fmv.w.x ft1, a0 65 | +; RV32IF-NEXT: fmul.s ft0, ft1, ft0 66 | +; RV32IF-NEXT: fmv.w.x ft1, a2 67 | +; RV32IF-NEXT: fadd.s ft0, ft0, ft1 68 | +; RV32IF-NEXT: fmv.x.w a0, ft0 69 | +; RV32IF-NEXT: jalr zero, ra, 0 70 | + %1 = call float @llvm.fmuladd.f32(float %a, float %b, float %c) 71 | + ret float %1 72 | +} 73 | + 74 | +define float @fmsub_s_fma_intrinsic(float %a, float %b, float %c) nounwind { 75 | +; TODO: the DAG combiner converts the fneg of a bitcasted value to a xor, 76 | +; meaning the fmsub pattern fails 77 | +; RV32IF-LABEL: fmsub_s_fma_intrinsic: 78 | +; RV32IF: # %bb.0: 79 | +; RV32IF-NEXT: lui a3, 524288 80 | +; RV32IF-NEXT: addi a3, a3, 0 81 | +; RV32IF-NEXT: xor a2, a2, a3 82 | +; RV32IF-NEXT: fmv.w.x ft0, a2 83 | +; RV32IF-NEXT: fmv.w.x ft1, a1 84 | +; RV32IF-NEXT: fmv.w.x ft2, a0 85 | +; RV32IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 86 | +; RV32IF-NEXT: fmv.x.w a0, ft0 87 | +; RV32IF-NEXT: jalr zero, ra, 0 88 | + %1 = fsub float -0.00, %c 89 | + %2 = call float @llvm.fma.f32(float %a, float %b, float %1) 90 | + ret float %2 91 | +} 92 | -- 93 | 2.16.2 94 | 95 | -------------------------------------------------------------------------------- /0081-RISCV-Define-getSetCCResultType-for-setting-vector-s.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Define getSetCCResultType for setting vector setCC type 4 | 5 | To avoid trigger "No default SetCC type for vectors!" Assertion 6 | 7 | Differential Revision: https://reviews.llvm.org/D42675 8 | Patch by Shiva Chen. 9 | --- 10 | lib/Target/RISCV/RISCVISelLowering.cpp | 7 ++++++ 11 | lib/Target/RISCV/RISCVISelLowering.h | 3 +++ 12 | test/CodeGen/RISCV/get-setcc-result-type.ll | 35 +++++++++++++++++++++++++++++ 13 | 3 files changed, 45 insertions(+) 14 | create mode 100644 test/CodeGen/RISCV/get-setcc-result-type.ll 15 | 16 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 17 | index bac74ee62c5..c48e76cf32b 100644 18 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 19 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 20 | @@ -229,6 +229,13 @@ void RISCVTargetLowering::computeKnownBitsForTargetNode( 21 | Known.One &= Known2.One; 22 | } 23 | 24 | +EVT RISCVTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &, 25 | + EVT VT) const { 26 | + if (!VT.isVector()) 27 | + return getPointerTy(DL); 28 | + return VT.changeVectorElementTypeToInteger(); 29 | +} 30 | + 31 | // Changes the condition code and swaps operands if necessary, so the SetCC 32 | // operation matches one of the comparisons supported directly in the RISC-V 33 | // ISA. 34 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 35 | index 807cb9c0b8d..f15853c76eb 100644 36 | --- a/lib/Target/RISCV/RISCVISelLowering.h 37 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 38 | @@ -79,6 +79,9 @@ public: 39 | Instruction *emitTrailingFence(IRBuilder<> &Builder, Instruction *Inst, 40 | AtomicOrdering Ord) const override; 41 | 42 | + EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, 43 | + EVT VT) const override; 44 | + 45 | private: 46 | void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, 47 | const SmallVectorImpl &Ins, 48 | diff --git a/test/CodeGen/RISCV/get-setcc-result-type.ll b/test/CodeGen/RISCV/get-setcc-result-type.ll 49 | new file mode 100644 50 | index 00000000000..003f3b367cf 51 | --- /dev/null 52 | +++ b/test/CodeGen/RISCV/get-setcc-result-type.ll 53 | @@ -0,0 +1,35 @@ 54 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 55 | +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ 56 | +; RUN: | FileCheck -check-prefix=RV32I %s 57 | + 58 | +define void @getSetCCResultType(<4 x i32>* %p, <4 x i32>* %q) { 59 | +; RV32I-LABEL: getSetCCResultType: 60 | +; RV32I: # %bb.0: # %entry 61 | +; RV32I-NEXT: lw a1, 12(a0) 62 | +; RV32I-NEXT: xor a1, a1, zero 63 | +; RV32I-NEXT: seqz a1, a1 64 | +; RV32I-NEXT: neg a1, a1 65 | +; RV32I-NEXT: sw a1, 12(a0) 66 | +; RV32I-NEXT: lw a1, 8(a0) 67 | +; RV32I-NEXT: xor a1, a1, zero 68 | +; RV32I-NEXT: seqz a1, a1 69 | +; RV32I-NEXT: neg a1, a1 70 | +; RV32I-NEXT: sw a1, 8(a0) 71 | +; RV32I-NEXT: lw a1, 4(a0) 72 | +; RV32I-NEXT: xor a1, a1, zero 73 | +; RV32I-NEXT: seqz a1, a1 74 | +; RV32I-NEXT: neg a1, a1 75 | +; RV32I-NEXT: sw a1, 4(a0) 76 | +; RV32I-NEXT: lw a1, 0(a0) 77 | +; RV32I-NEXT: xor a1, a1, zero 78 | +; RV32I-NEXT: seqz a1, a1 79 | +; RV32I-NEXT: neg a1, a1 80 | +; RV32I-NEXT: sw a1, 0(a0) 81 | +; RV32I-NEXT: ret 82 | +entry: 83 | + %0 = load <4 x i32>, <4 x i32>* %p, align 16 84 | + %cmp = icmp eq <4 x i32> %0, zeroinitializer 85 | + %sext = sext <4 x i1> %cmp to <4 x i32> 86 | + store <4 x i32> %sext, <4 x i32>* %p, align 16 87 | + ret void 88 | +} 89 | -- 90 | 2.16.2 91 | 92 | -------------------------------------------------------------------------------- /docs/02-starting-the-backend.mkd: -------------------------------------------------------------------------------- 1 | # Starting the new backend 2 | 3 | ## Add support for the target triple 4 | 5 | The very first step is to add support for recognising the architecture name in 6 | the target-independent "triple" parsing code. The triple is used to identify 7 | the architecture, vendor, operating system and sometimes environment. For 8 | RISC-V, there are two architecture names to recognise - riscv32 and riscv64. 9 | 10 | Necessary changes include adding riscv32 and riscv64 to: 11 | * The `Triple::ArchType` enum 12 | * `Triple::getArchTypeName`, `Triple::getArchTypePrefix`, 13 | `Triple::getArchTypeForLLVMName`, and `Triple::parseArch` 14 | * Helper functions such as `Triple::getDefaultFormat` (returning 15 | `Triple::ELF`), `Triple::getArchPointerBitWidth`, `Triple::isLittleEndian` 16 | * Most importantly, test all of the above by modifying 17 | `unittests/ADT/TripleTest.cpp` 18 | 19 | See the patch for a full listing: 20 | 21 | {{% showpatch "recognise riscv32 riscv64 triple parsing" %}} 22 | 23 | You can now run the tests using lit (as described in the first part of this 24 | tutorial), and commit the patch. 25 | 26 | ## Support for RISC-V ELF files 27 | 28 | The final step before getting started on the backend itself is to add the 29 | necessary definitions for RISC-V ELF files. This includes: 30 | * Adding the relocation types to 31 | `include/llvm/BinaryFormat/ELFRelocs/RISCV.def` 32 | * Adding the `EM_RISCV` machine definition (see 33 | [here](http://www.sco.com/developers/gabi/latest/ch4.eheader.html) for a 34 | reference list) 35 | * Adding `EM_RISCV` to various case statements in 36 | `include/llvm/Object/ELFObjectFile.h`. Some architectures have a different 37 | `EM_*` constant for 32-bit vs 64-bit, but RISC-V (like MIPS) uses the 38 | `EI_CLASS` ELF field to determine whether an object file is for a 32-bit of 39 | 64-bit machine 40 | * Adding `EM_RISCV` to case statements in ELFYAML, llvm-objdump and 41 | llvm-readobj 42 | 43 | See the patch for full details: 44 | 45 | {{% showpatch "add RISC-V ELF defines" %}} 46 | 47 | ## Adding a skeleton backend 48 | 49 | The next step is to add a "skeleton" backend, i.e. enough code in 50 | `lib/Target/RISCV` that the backend will compile and link. This involves: 51 | * Registering the RISC-V backend with the LLVM buildsystem 52 | * Adding a stub `RISCVTargetMachine.{cpp,h}` 53 | * Adding a stub `RISCVTargetInfo.cpp` which will register the target 54 | 55 | The most interesting part of `RISCVTargetMachine` is probably the 56 | `computeDataLayout` helper. This returns a datalayout string appropriate to 57 | the machine (riscv32 or riscv64). For instance, the riscv32 datalayout string 58 | is `"e-m:e-p:32:32-i64:64-n32-S128"`. To pull this apart, this string means: 59 | 60 | * `e`: little-endian 61 | * `m:e`: ELF mangling mode 62 | * `p:32:32`: pointers are 32-bit wide and have 32-bit alignment 63 | * `i64:64`: 64-bit integers have 64-bit alignment 64 | * `n32`: the native integer type is 32-bit 65 | * `S128`: the stack's natural alignment is 128 bits (16 bytes) 66 | 67 | You can now build the backend. CMake must be re-run, with RISCV specified in 68 | `LLVM_EXPERIMENTAL_TARGETS_TO_BUILD`. 69 | 70 | cmake -G Ninja -DCMAKE_BUILD_TYPE="Debug" \ 71 | -DBUILD_SHARED_LIBS=True -DLLVM_USE_SPLIT_DWARF=True \ 72 | -DLLVM_OPTIMIZED_TABLEGEN=True \ 73 | -DLLVM_BUILD_TESTS=True \ 74 | -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ 75 | -DLLVM_TARGETS_TO_BUILD="X86" \ 76 | -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="RISCV" ../ 77 | cmake --build . 78 | 79 | You can check the target was included and registered correctly by checking the 80 | output of a command like `./bin/llvm/as --version`, which should list riscv32 81 | and riscv64 as registered targets. Of course, the RISC-V backend is just a 82 | stub at this point, so trying something like `./bin/llc -march=riscv64 83 | ../test/Object/Inputs/trivial.ll` will fail immediately with an assertion. 84 | -------------------------------------------------------------------------------- /0024-RISCV-Allow-lowering-of-dynamic_stackalloc-stacksave.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Allow lowering of dynamic_stackalloc, stacksave, stackrestore 4 | 5 | --- 6 | lib/Target/RISCV/RISCVISelLowering.cpp | 5 +++ 7 | test/CodeGen/RISCV/alloca.ll | 65 ++++++++++++++++++++++++++++++++++ 8 | 2 files changed, 70 insertions(+) 9 | create mode 100644 test/CodeGen/RISCV/alloca.ll 10 | 11 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 12 | index 4801884e242..58817533925 100644 13 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 14 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 15 | @@ -53,11 +53,16 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, 16 | setLoadExtAction(N, XLenVT, MVT::i1, Promote); 17 | 18 | // TODO: add all necessary setOperationAction calls. 19 | + setOperationAction(ISD::DYNAMIC_STACKALLOC, XLenVT, Expand); 20 | + 21 | setOperationAction(ISD::BR_JT, MVT::Other, Expand); 22 | setOperationAction(ISD::BR_CC, XLenVT, Expand); 23 | setOperationAction(ISD::SELECT, XLenVT, Custom); 24 | setOperationAction(ISD::SELECT_CC, XLenVT, Expand); 25 | 26 | + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 27 | + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 28 | + 29 | for (auto VT : {MVT::i1, MVT::i8, MVT::i16}) 30 | setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand); 31 | 32 | diff --git a/test/CodeGen/RISCV/alloca.ll b/test/CodeGen/RISCV/alloca.ll 33 | new file mode 100644 34 | index 00000000000..7815866f5c4 35 | --- /dev/null 36 | +++ b/test/CodeGen/RISCV/alloca.ll 37 | @@ -0,0 +1,65 @@ 38 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 39 | +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ 40 | +; RUN: | FileCheck %s -check-prefix=RV32I 41 | + 42 | +declare void @notdead(i8*) 43 | + 44 | +; These tests must ensure the stack pointer is restored using the frame 45 | +; pointer 46 | + 47 | +define void @simple_alloca(i32 %n) nounwind { 48 | +; RV32I-LABEL: simple_alloca: 49 | +; RV32I: # %bb.0: 50 | +; RV32I-NEXT: addi sp, sp, -16 51 | +; RV32I-NEXT: sw ra, 12(sp) 52 | +; RV32I-NEXT: sw s0, 8(sp) 53 | +; RV32I-NEXT: addi s0, sp, 16 54 | +; RV32I-NEXT: addi a0, a0, 15 55 | +; RV32I-NEXT: andi a0, a0, -16 56 | +; RV32I-NEXT: sub a0, sp, a0 57 | +; RV32I-NEXT: addi sp, a0, 0 58 | +; RV32I-NEXT: lui a1, %hi(notdead) 59 | +; RV32I-NEXT: addi a1, a1, %lo(notdead) 60 | +; RV32I-NEXT: jalr ra, a1, 0 61 | +; RV32I-NEXT: addi sp, s0, -16 62 | +; RV32I-NEXT: lw s0, 8(sp) 63 | +; RV32I-NEXT: lw ra, 12(sp) 64 | +; RV32I-NEXT: addi sp, sp, 16 65 | +; RV32I-NEXT: jalr zero, ra, 0 66 | + %1 = alloca i8, i32 %n 67 | + call void @notdead(i8* %1) 68 | + ret void 69 | +} 70 | + 71 | +declare i8* @llvm.stacksave() 72 | +declare void @llvm.stackrestore(i8*) 73 | + 74 | +define void @scoped_alloca(i32 %n) nounwind { 75 | +; RV32I-LABEL: scoped_alloca: 76 | +; RV32I: # %bb.0: 77 | +; RV32I-NEXT: addi sp, sp, -16 78 | +; RV32I-NEXT: sw ra, 12(sp) 79 | +; RV32I-NEXT: sw s0, 8(sp) 80 | +; RV32I-NEXT: sw s1, 4(sp) 81 | +; RV32I-NEXT: addi s0, sp, 16 82 | +; RV32I-NEXT: addi s1, sp, 0 83 | +; RV32I-NEXT: addi a0, a0, 15 84 | +; RV32I-NEXT: andi a0, a0, -16 85 | +; RV32I-NEXT: sub a0, sp, a0 86 | +; RV32I-NEXT: addi sp, a0, 0 87 | +; RV32I-NEXT: lui a1, %hi(notdead) 88 | +; RV32I-NEXT: addi a1, a1, %lo(notdead) 89 | +; RV32I-NEXT: jalr ra, a1, 0 90 | +; RV32I-NEXT: addi sp, s1, 0 91 | +; RV32I-NEXT: addi sp, s0, -16 92 | +; RV32I-NEXT: lw s1, 4(sp) 93 | +; RV32I-NEXT: lw s0, 8(sp) 94 | +; RV32I-NEXT: lw ra, 12(sp) 95 | +; RV32I-NEXT: addi sp, sp, 16 96 | +; RV32I-NEXT: jalr zero, ra, 0 97 | + %sp = call i8* @llvm.stacksave() 98 | + %addr = alloca i8, i32 %n 99 | + call void @notdead(i8* %addr) 100 | + call void @llvm.stackrestore(i8* %sp) 101 | + ret void 102 | +} 103 | -- 104 | 2.16.2 105 | 106 | -------------------------------------------------------------------------------- /0079-RISCV-Allow-RISCVAsmBackend-writeNopData-to-generate.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Allow RISCVAsmBackend::writeNopData to generate c.nop when 4 | supported 5 | 6 | When the compressed instruction set is enabled, the 16-bit c.nop can be 7 | generated if necessary. 8 | 9 | Differential Revision: https://reviews.llvm.org/D41221 10 | Patch by Shiva Chen. 11 | --- 12 | lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 26 ++++++++++++++++------- 13 | test/MC/RISCV/cnop.s | 26 +++++++++++++++++++++++ 14 | 2 files changed, 44 insertions(+), 8 deletions(-) 15 | create mode 100644 test/MC/RISCV/cnop.s 16 | 17 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp 18 | index 6e06a4975e2..3dcd36f1b71 100644 19 | --- a/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp 20 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp 21 | @@ -27,12 +27,13 @@ using namespace llvm; 22 | 23 | namespace { 24 | class RISCVAsmBackend : public MCAsmBackend { 25 | + const MCSubtargetInfo &STI; 26 | uint8_t OSABI; 27 | bool Is64Bit; 28 | 29 | public: 30 | - RISCVAsmBackend(uint8_t OSABI, bool Is64Bit) 31 | - : MCAsmBackend(), OSABI(OSABI), Is64Bit(Is64Bit) {} 32 | + RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit) 33 | + : MCAsmBackend(), STI(STI), OSABI(OSABI), Is64Bit(Is64Bit) {} 34 | ~RISCVAsmBackend() override {} 35 | 36 | void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, 37 | @@ -88,15 +89,24 @@ public: 38 | }; 39 | 40 | bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { 41 | - // Once support for the compressed instruction set is added, we will be able 42 | - // to conditionally support 16-bit NOPs 43 | - if ((Count % 4) != 0) 44 | + bool HasStdExtC = STI.getFeatureBits()[RISCV::FeatureStdExtC]; 45 | + unsigned MinNopLen = HasStdExtC ? 2 : 4; 46 | + 47 | + if ((Count % MinNopLen) != 0) 48 | return false; 49 | 50 | - // The canonical nop on RISC-V is addi x0, x0, 0 51 | - for (uint64_t i = 0; i < Count; i += 4) 52 | + // The canonical nop on RISC-V is addi x0, x0, 0. 53 | + uint64_t Nop32Count = Count / 4; 54 | + for (uint64_t i = Nop32Count; i != 0; --i) 55 | OW->write32(0x13); 56 | 57 | + // The canonical nop on RVC is c.nop. 58 | + if (HasStdExtC) { 59 | + uint64_t Nop16Count = (Count - Nop32Count * 4) / 2; 60 | + for (uint64_t i = Nop16Count; i != 0; --i) 61 | + OW->write16(0x01); 62 | + } 63 | + 64 | return true; 65 | } 66 | 67 | @@ -235,5 +245,5 @@ MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T, 68 | const MCTargetOptions &Options) { 69 | const Triple &TT = STI.getTargetTriple(); 70 | uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); 71 | - return new RISCVAsmBackend(OSABI, TT.isArch64Bit()); 72 | + return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit()); 73 | } 74 | diff --git a/test/MC/RISCV/cnop.s b/test/MC/RISCV/cnop.s 75 | new file mode 100644 76 | index 00000000000..8d526263724 77 | --- /dev/null 78 | +++ b/test/MC/RISCV/cnop.s 79 | @@ -0,0 +1,26 @@ 80 | +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \ 81 | +# RUN: | llvm-objdump -mattr=+c -d - | FileCheck -check-prefix=CHECK-INST %s 82 | + 83 | +# alpha and main are 8 byte alignment 84 | +# but the alpha function's size is 6 85 | +# So assembler will insert a c.nop to make sure 8 byte alignment. 86 | + 87 | + .text 88 | + .p2align 3 89 | + .type alpha,@function 90 | +alpha: 91 | +# BB#0: 92 | + addi sp, sp, -16 93 | + c.lw a0, 0(a0) 94 | +# CHECK-INST: c.nop 95 | +.Lfunc_end0: 96 | + .size alpha, .Lfunc_end0-alpha 97 | + # -- End function 98 | + .globl main 99 | + .p2align 3 100 | + .type main,@function 101 | +main: # @main 102 | +# BB#0: 103 | +.Lfunc_end1: 104 | + .size main, .Lfunc_end1-main 105 | + # -- End function 106 | -- 107 | 2.16.2 108 | 109 | -------------------------------------------------------------------------------- /0014-RISCV-Codegen-support-for-materializing-constants.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Codegen support for materializing constants 4 | 5 | --- 6 | lib/Target/RISCV/RISCVInstrInfo.td | 24 +++++++++++++++++++ 7 | test/CodeGen/RISCV/alu32.ll | 1 - 8 | test/CodeGen/RISCV/imm.ll | 47 ++++++++++++++++++++++++++++++++++++++ 9 | 3 files changed, 71 insertions(+), 1 deletion(-) 10 | create mode 100644 test/CodeGen/RISCV/imm.ll 11 | 12 | diff --git a/lib/Target/RISCV/RISCVInstrInfo.td b/lib/Target/RISCV/RISCVInstrInfo.td 13 | index 616e6042070..3c7bc8bd3ed 100644 14 | --- a/lib/Target/RISCV/RISCVInstrInfo.td 15 | +++ b/lib/Target/RISCV/RISCVInstrInfo.td 16 | @@ -86,6 +86,24 @@ def simm21_lsb0 : Operand { 17 | let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; 18 | } 19 | 20 | +// Standalone (codegen-only) immleaf patterns. 21 | +def simm32 : ImmLeaf(Imm);}]>; 22 | + 23 | +// Extract least significant 12 bits from an immediate value and sign extend 24 | +// them. 25 | +def LO12Sext : SDNodeXFormgetTargetConstant(SignExtend64<12>(N->getZExtValue()), 27 | + SDLoc(N), N->getValueType(0)); 28 | +}]>; 29 | + 30 | +// Extract the most significant 20 bits from an immediate value. Add 1 if bit 31 | +// 11 is 1, to compensate for the low 12 bits in the matching immediate addi 32 | +// or ld/st being negative. 33 | +def HI20 : SDNodeXFormgetTargetConstant(((N->getZExtValue()+0x800) >> 12) & 0xfffff, 35 | + SDLoc(N), N->getValueType(0)); 36 | +}]>; 37 | + 38 | //===----------------------------------------------------------------------===// 39 | // Instruction Class Templates 40 | //===----------------------------------------------------------------------===// 41 | @@ -257,6 +275,12 @@ class PatGprUimm5 42 | : Pat<(OpNode GPR:$rs1, uimm5:$shamt), 43 | (Inst GPR:$rs1, uimm5:$shamt)>; 44 | 45 | +/// Immediates 46 | + 47 | +def : Pat<(simm12:$imm), (ADDI X0, simm12:$imm)>; 48 | +// TODO: Add a pattern for immediates with all zeroes in the lower 12 bits. 49 | +def : Pat<(simm32:$imm), (ADDI (LUI (HI20 imm:$imm)), (LO12Sext imm:$imm))>; 50 | + 51 | /// Simple arithmetic operations 52 | 53 | def : PatGprGpr; 54 | diff --git a/test/CodeGen/RISCV/alu32.ll b/test/CodeGen/RISCV/alu32.ll 55 | index f0a0e6c6ad8..3a3128315e1 100644 56 | --- a/test/CodeGen/RISCV/alu32.ll 57 | +++ b/test/CodeGen/RISCV/alu32.ll 58 | @@ -9,7 +9,6 @@ define i32 @addi(i32 %a) nounwind { 59 | ; RV32I: # %bb.0: 60 | ; RV32I-NEXT: addi a0, a0, 1 61 | ; RV32I-NEXT: jalr zero, ra, 0 62 | -; TODO: check support for materialising larger constants 63 | %1 = add i32 %a, 1 64 | ret i32 %1 65 | } 66 | diff --git a/test/CodeGen/RISCV/imm.ll b/test/CodeGen/RISCV/imm.ll 67 | new file mode 100644 68 | index 00000000000..ddefa22835a 69 | --- /dev/null 70 | +++ b/test/CodeGen/RISCV/imm.ll 71 | @@ -0,0 +1,47 @@ 72 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 73 | +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ 74 | +; RUN: | FileCheck %s -check-prefix=RV32I 75 | + 76 | +; Materializing constants 77 | + 78 | +define i32 @zero() nounwind { 79 | +; RV32I-LABEL: zero: 80 | +; RV32I: # %bb.0: 81 | +; RV32I-NEXT: addi a0, zero, 0 82 | +; RV32I-NEXT: jalr zero, ra, 0 83 | + ret i32 0 84 | +} 85 | + 86 | +define i32 @pos_small() nounwind { 87 | +; RV32I-LABEL: pos_small: 88 | +; RV32I: # %bb.0: 89 | +; RV32I-NEXT: addi a0, zero, 2047 90 | +; RV32I-NEXT: jalr zero, ra, 0 91 | + ret i32 2047 92 | +} 93 | + 94 | +define i32 @neg_small() nounwind { 95 | +; RV32I-LABEL: neg_small: 96 | +; RV32I: # %bb.0: 97 | +; RV32I-NEXT: addi a0, zero, -2048 98 | +; RV32I-NEXT: jalr zero, ra, 0 99 | + ret i32 -2048 100 | +} 101 | + 102 | +define i32 @pos_i32() nounwind { 103 | +; RV32I-LABEL: pos_i32: 104 | +; RV32I: # %bb.0: 105 | +; RV32I-NEXT: lui a0, 423811 106 | +; RV32I-NEXT: addi a0, a0, -1297 107 | +; RV32I-NEXT: jalr zero, ra, 0 108 | + ret i32 1735928559 109 | +} 110 | + 111 | +define i32 @neg_i32() nounwind { 112 | +; RV32I-LABEL: neg_i32: 113 | +; RV32I: # %bb.0: 114 | +; RV32I-NEXT: lui a0, 912092 115 | +; RV32I-NEXT: addi a0, a0, -273 116 | +; RV32I-NEXT: jalr zero, ra, 0 117 | + ret i32 -559038737 118 | +} 119 | -- 120 | 2.16.2 121 | 122 | -------------------------------------------------------------------------------- /0051-RISCV-Codegen-support-for-FPR32-stack-loads-stores.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Codegen support for FPR32<->stack loads/stores 4 | 5 | --- 6 | lib/Target/RISCV/RISCVInstrInfo.cpp | 34 ++++++++++++++--------- 7 | test/CodeGen/RISCV/float-mem.ll | 55 +++++++++++++++++++++++++++++++++++++ 8 | 2 files changed, 76 insertions(+), 13 deletions(-) 9 | 10 | diff --git a/lib/Target/RISCV/RISCVInstrInfo.cpp b/lib/Target/RISCV/RISCVInstrInfo.cpp 11 | index e2fc3ad91e0..b630fb87286 100644 12 | --- a/lib/Target/RISCV/RISCVInstrInfo.cpp 13 | +++ b/lib/Target/RISCV/RISCVInstrInfo.cpp 14 | @@ -54,15 +54,19 @@ void RISCVInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, 15 | if (I != MBB.end()) 16 | DL = I->getDebugLoc(); 17 | 18 | - if (RISCV::GPRRegClass.hasSubClassEq(RC)) { 19 | - unsigned Opcode = Subtarget.is64Bit() ? RISCV::SD : RISCV::SW; 20 | - BuildMI(MBB, I, DL, get(Opcode)) 21 | - .addReg(SrcReg, getKillRegState(IsKill)) 22 | - .addFrameIndex(FI) 23 | - .addImm(0); 24 | - } else { 25 | + unsigned Opcode; 26 | + 27 | + if (RISCV::GPRRegClass.hasSubClassEq(RC)) 28 | + Opcode = Subtarget.is64Bit() ? RISCV::SD : RISCV::SW; 29 | + else if (RISCV::FPR32RegClass.hasSubClassEq(RC)) 30 | + Opcode = RISCV::FSW; 31 | + else 32 | llvm_unreachable("Can't store this register to stack slot"); 33 | - } 34 | + 35 | + BuildMI(MBB, I, DL, get(Opcode)) 36 | + .addReg(SrcReg, getKillRegState(IsKill)) 37 | + .addFrameIndex(FI) 38 | + .addImm(0); 39 | } 40 | 41 | void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 42 | @@ -74,12 +78,16 @@ void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 43 | if (I != MBB.end()) 44 | DL = I->getDebugLoc(); 45 | 46 | - if (RISCV::GPRRegClass.hasSubClassEq(RC)) { 47 | - unsigned Opcode = Subtarget.is64Bit() ? RISCV::LD : RISCV::LW; 48 | - BuildMI(MBB, I, DL, get(Opcode), DstReg).addFrameIndex(FI).addImm(0); 49 | - } else { 50 | + unsigned Opcode; 51 | + 52 | + if (RISCV::GPRRegClass.hasSubClassEq(RC)) 53 | + Opcode = Subtarget.is64Bit() ? RISCV::LD : RISCV::LW; 54 | + else if (RISCV::FPR32RegClass.hasSubClassEq(RC)) 55 | + Opcode = RISCV::FLW; 56 | + else 57 | llvm_unreachable("Can't load this register from stack slot"); 58 | - } 59 | + 60 | + BuildMI(MBB, I, DL, get(Opcode), DstReg).addFrameIndex(FI).addImm(0); 61 | } 62 | 63 | void RISCVInstrInfo::movImm32(MachineBasicBlock &MBB, 64 | diff --git a/test/CodeGen/RISCV/float-mem.ll b/test/CodeGen/RISCV/float-mem.ll 65 | index f1cbb4330f3..0f543ef083f 100644 66 | --- a/test/CodeGen/RISCV/float-mem.ll 67 | +++ b/test/CodeGen/RISCV/float-mem.ll 68 | @@ -82,3 +82,58 @@ define float @flw_fsw_constant(float %a) nounwind { 69 | store float %3, float* %1 70 | ret float %3 71 | } 72 | + 73 | +declare void @notdead(i8*) 74 | + 75 | +define float @flw_stack(float %a) nounwind { 76 | +; Tests RISCV::LdFPR32_FI 77 | +; RV32IF-LABEL: flw_stack: 78 | +; RV32IF: # %bb.0: 79 | +; RV32IF-NEXT: addi sp, sp, -16 80 | +; RV32IF-NEXT: sw ra, 12(sp) 81 | +; RV32IF-NEXT: sw s1, 8(sp) 82 | +; RV32IF-NEXT: addi s1, a0, 0 83 | +; RV32IF-NEXT: lui a0, %hi(notdead) 84 | +; RV32IF-NEXT: addi a1, a0, %lo(notdead) 85 | +; RV32IF-NEXT: addi a0, sp, 4 86 | +; RV32IF-NEXT: jalr ra, a1, 0 87 | +; RV32IF-NEXT: fmv.w.x ft0, s1 88 | +; RV32IF-NEXT: flw ft1, 4(sp) 89 | +; RV32IF-NEXT: fadd.s ft0, ft1, ft0 90 | +; RV32IF-NEXT: fmv.x.w a0, ft0 91 | +; RV32IF-NEXT: lw s1, 8(sp) 92 | +; RV32IF-NEXT: lw ra, 12(sp) 93 | +; RV32IF-NEXT: addi sp, sp, 16 94 | +; RV32IF-NEXT: jalr zero, ra, 0 95 | + %1 = alloca float, align 4 96 | + %2 = bitcast float* %1 to i8* 97 | + call void @notdead(i8* %2) 98 | + %3 = load float, float* %1 99 | + %4 = fadd float %3, %a ; force load in to FPR32 100 | + ret float %4 101 | +} 102 | + 103 | +define void @fsw_stack(float %a, float %b) nounwind { 104 | +; Tests RISCV::StFPR32_FI 105 | +; RV32IF-LABEL: fsw_stack: 106 | +; RV32IF: # %bb.0: 107 | +; RV32IF-NEXT: addi sp, sp, -16 108 | +; RV32IF-NEXT: sw ra, 12(sp) 109 | +; RV32IF-NEXT: fmv.w.x ft0, a1 110 | +; RV32IF-NEXT: fmv.w.x ft1, a0 111 | +; RV32IF-NEXT: fadd.s ft0, ft1, ft0 112 | +; RV32IF-NEXT: fsw ft0, 8(sp) 113 | +; RV32IF-NEXT: lui a0, %hi(notdead) 114 | +; RV32IF-NEXT: addi a1, a0, %lo(notdead) 115 | +; RV32IF-NEXT: addi a0, sp, 8 116 | +; RV32IF-NEXT: jalr ra, a1, 0 117 | +; RV32IF-NEXT: lw ra, 12(sp) 118 | +; RV32IF-NEXT: addi sp, sp, 16 119 | +; RV32IF-NEXT: jalr zero, ra, 0 120 | + %1 = fadd float %a, %b ; force store from FPR32 121 | + %2 = alloca float, align 4 122 | + store float %1, float* %2 123 | + %3 = bitcast float* %2 to i8* 124 | + call void @notdead(i8* %3) 125 | + ret void 126 | +} 127 | -- 128 | 2.16.2 129 | 130 | -------------------------------------------------------------------------------- /0056-RISCV-Codegen-support-for-RV32D-floating-point-conve.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Codegen support for RV32D floating point conversion 4 | operations 5 | 6 | --- 7 | lib/Target/RISCV/RISCVInstrInfoD.td | 14 ++++++ 8 | test/CodeGen/RISCV/double-convert.ll | 89 ++++++++++++++++++++++++++++++++++++ 9 | 2 files changed, 103 insertions(+) 10 | create mode 100644 test/CodeGen/RISCV/double-convert.ll 11 | 12 | diff --git a/lib/Target/RISCV/RISCVInstrInfoD.td b/lib/Target/RISCV/RISCVInstrInfoD.td 13 | index b6b47c97e85..4cb5a30d03e 100644 14 | --- a/lib/Target/RISCV/RISCVInstrInfoD.td 15 | +++ b/lib/Target/RISCV/RISCVInstrInfoD.td 16 | @@ -172,6 +172,20 @@ class PatFpr64Fpr64DynFrm 17 | 18 | let Predicates = [HasStdExtD] in { 19 | 20 | +/// Float conversion operations 21 | + 22 | +// f64 -> f32, f32 -> f64 23 | +def : Pat<(fpround FPR64:$rs1), (FCVT_S_D FPR64:$rs1, 0b111)>; 24 | +def : Pat<(fpextend FPR32:$rs1), (FCVT_D_S FPR32:$rs1)>; 25 | + 26 | +// FP->[u]int. Round-to-zero must be used 27 | +def : Pat<(fp_to_sint FPR64:$rs1), (FCVT_W_D FPR64:$rs1, 0b001)>; 28 | +def : Pat<(fp_to_uint FPR64:$rs1), (FCVT_WU_D FPR64:$rs1, 0b001)>; 29 | + 30 | +// [u]int->fp 31 | +def : Pat<(sint_to_fp GPR:$rs1), (FCVT_D_W GPR:$rs1)>; 32 | +def : Pat<(uint_to_fp GPR:$rs1), (FCVT_D_WU GPR:$rs1)>; 33 | + 34 | /// Float arithmetic operations 35 | 36 | def : PatFpr64Fpr64DynFrm; 37 | diff --git a/test/CodeGen/RISCV/double-convert.ll b/test/CodeGen/RISCV/double-convert.ll 38 | new file mode 100644 39 | index 00000000000..4b2c9707aa4 40 | --- /dev/null 41 | +++ b/test/CodeGen/RISCV/double-convert.ll 42 | @@ -0,0 +1,89 @@ 43 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 44 | +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ 45 | +; RUN: | FileCheck -check-prefix=RV32IFD %s 46 | + 47 | +define float @fcvt_s_d(double %a) nounwind { 48 | +; RV32IFD-LABEL: fcvt_s_d: 49 | +; RV32IFD: # %bb.0: 50 | +; RV32IFD-NEXT: addi sp, sp, -16 51 | +; RV32IFD-NEXT: sw a1, 12(sp) 52 | +; RV32IFD-NEXT: sw a0, 8(sp) 53 | +; RV32IFD-NEXT: fld ft0, 8(sp) 54 | +; RV32IFD-NEXT: fcvt.s.d ft0, ft0 55 | +; RV32IFD-NEXT: fmv.x.w a0, ft0 56 | +; RV32IFD-NEXT: addi sp, sp, 16 57 | +; RV32IFD-NEXT: jalr zero, ra, 0 58 | + %1 = fptrunc double %a to float 59 | + ret float %1 60 | +} 61 | + 62 | +define double @fcvt_d_s(float %a) nounwind { 63 | +; RV32IFD-LABEL: fcvt_d_s: 64 | +; RV32IFD: # %bb.0: 65 | +; RV32IFD-NEXT: addi sp, sp, -16 66 | +; RV32IFD-NEXT: fmv.w.x ft0, a0 67 | +; RV32IFD-NEXT: fcvt.d.s ft0, ft0 68 | +; RV32IFD-NEXT: fsd ft0, 8(sp) 69 | +; RV32IFD-NEXT: lw a0, 8(sp) 70 | +; RV32IFD-NEXT: lw a1, 12(sp) 71 | +; RV32IFD-NEXT: addi sp, sp, 16 72 | +; RV32IFD-NEXT: jalr zero, ra, 0 73 | + %1 = fpext float %a to double 74 | + ret double %1 75 | +} 76 | + 77 | +define i32 @fcvt_w_d(double %a) nounwind { 78 | +; RV32IFD-LABEL: fcvt_w_d: 79 | +; RV32IFD: # %bb.0: 80 | +; RV32IFD-NEXT: addi sp, sp, -16 81 | +; RV32IFD-NEXT: sw a1, 12(sp) 82 | +; RV32IFD-NEXT: sw a0, 8(sp) 83 | +; RV32IFD-NEXT: fld ft0, 8(sp) 84 | +; RV32IFD-NEXT: fcvt.w.d a0, ft0, rtz 85 | +; RV32IFD-NEXT: addi sp, sp, 16 86 | +; RV32IFD-NEXT: jalr zero, ra, 0 87 | + %1 = fptosi double %a to i32 88 | + ret i32 %1 89 | +} 90 | + 91 | +define i32 @fcvt_wu_d(double %a) nounwind { 92 | +; RV32IFD-LABEL: fcvt_wu_d: 93 | +; RV32IFD: # %bb.0: 94 | +; RV32IFD-NEXT: addi sp, sp, -16 95 | +; RV32IFD-NEXT: sw a1, 12(sp) 96 | +; RV32IFD-NEXT: sw a0, 8(sp) 97 | +; RV32IFD-NEXT: fld ft0, 8(sp) 98 | +; RV32IFD-NEXT: fcvt.wu.d a0, ft0, rtz 99 | +; RV32IFD-NEXT: addi sp, sp, 16 100 | +; RV32IFD-NEXT: jalr zero, ra, 0 101 | + %1 = fptoui double %a to i32 102 | + ret i32 %1 103 | +} 104 | + 105 | +define double @fcvt_d_w(i32 %a) nounwind { 106 | +; RV32IFD-LABEL: fcvt_d_w: 107 | +; RV32IFD: # %bb.0: 108 | +; RV32IFD-NEXT: addi sp, sp, -16 109 | +; RV32IFD-NEXT: fcvt.d.w ft0, a0 110 | +; RV32IFD-NEXT: fsd ft0, 8(sp) 111 | +; RV32IFD-NEXT: lw a0, 8(sp) 112 | +; RV32IFD-NEXT: lw a1, 12(sp) 113 | +; RV32IFD-NEXT: addi sp, sp, 16 114 | +; RV32IFD-NEXT: jalr zero, ra, 0 115 | + %1 = sitofp i32 %a to double 116 | + ret double %1 117 | +} 118 | + 119 | +define double @fcvt_d_wu(i32 %a) nounwind { 120 | +; RV32IFD-LABEL: fcvt_d_wu: 121 | +; RV32IFD: # %bb.0: 122 | +; RV32IFD-NEXT: addi sp, sp, -16 123 | +; RV32IFD-NEXT: fcvt.d.wu ft0, a0 124 | +; RV32IFD-NEXT: fsd ft0, 8(sp) 125 | +; RV32IFD-NEXT: lw a0, 8(sp) 126 | +; RV32IFD-NEXT: lw a1, 12(sp) 127 | +; RV32IFD-NEXT: addi sp, sp, 16 128 | +; RV32IFD-NEXT: jalr zero, ra, 0 129 | + %1 = uitofp i32 %a to double 130 | + ret double %1 131 | +} 132 | -- 133 | 2.16.2 134 | 135 | -------------------------------------------------------------------------------- /scripts/run_torture_suite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COMPSUCC=0 4 | COMPFAIL=0 5 | RUNSUCC=0 6 | RUNFAIL=0 7 | rm -f comppass compfail runpass runfail 8 | touch comppass compfail runpass runfail 9 | mkdir -p output output/ieee 10 | rm -f output/* output/ieee/* 11 | 12 | TESTS_TO_SKIP=$(cat < skip.txt 169 | $TESTS_TO_SKIP 170 | EOF 171 | ) 172 | 173 | TESTS=$(comm -23 - <> comppass 200 | COMPSUCC=$((COMPSUCC + 1)) 201 | 202 | timelimit -s1 -t 4 spike pk output/$BASEFILE 203 | if [ $? -eq 0 ]; then 204 | echo ":)"; 205 | echo $BASEFILE >> runpass 206 | RUNSUCC=$((RUNSUCC + 1)) 207 | else 208 | echo ":(" 209 | echo $BASEFILE >> runfail 210 | RUNFAIL=$((RUNFAIL + 1)) 211 | fi 212 | else 213 | echo ":(" 214 | echo $BASEFILE >> compfail 215 | COMPFAIL=$((COMPFAIL + 1)) 216 | fi 217 | printf "\n\nCompile pass:fail %d:%d\n" $COMPSUCC $COMPFAIL 218 | printf "Run pass:fail %d:%d\n\n\n" $RUNSUCC $RUNFAIL 219 | done 220 | -------------------------------------------------------------------------------- /0064-RISCV-MC-layer-support-for-the-instructions-added-in.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] MC layer support for the instructions added in the privileged 4 | spec 5 | 6 | Adds support for the instructions added in the RISC-V privileged ISA 7 | (https://content.riscv.org/wp-content/uploads/2017/05/riscv-privileged-v1.10.pdf): 8 | uret, sret, mret, wfi, and sfence.vma. 9 | 10 | The commiter (asb) made very minor formatting changes prior to commit. 11 | 12 | Differential Revision: https://reviews.llvm.org/D40383 13 | 14 | Patch by David Craven. 15 | --- 16 | lib/Target/RISCV/RISCVInstrInfo.td | 42 ++++++++++++++++++++++++++++++++++++++ 17 | test/MC/RISCV/priv-invalid.s | 7 +++++++ 18 | test/MC/RISCV/priv-valid.s | 32 +++++++++++++++++++++++++++++ 19 | 3 files changed, 81 insertions(+) 20 | create mode 100644 test/MC/RISCV/priv-invalid.s 21 | create mode 100644 test/MC/RISCV/priv-valid.s 22 | 23 | diff --git a/lib/Target/RISCV/RISCVInstrInfo.td b/lib/Target/RISCV/RISCVInstrInfo.td 24 | index fd78c6eaf0b..447100682e4 100644 25 | --- a/lib/Target/RISCV/RISCVInstrInfo.td 26 | +++ b/lib/Target/RISCV/RISCVInstrInfo.td 27 | @@ -228,6 +228,11 @@ class ALUW_rr funct7, bits<3> funct3, string opcodestr> 28 | : RVInstR; 30 | 31 | +let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in 32 | +class Priv funct7> 33 | + : RVInstR; 35 | + 36 | //===----------------------------------------------------------------------===// 37 | // Instructions 38 | //===----------------------------------------------------------------------===// 39 | @@ -350,6 +355,43 @@ def SRLW : ALUW_rr<0b0000000, 0b101, "srlw">; 40 | def SRAW : ALUW_rr<0b0100000, 0b101, "sraw">; 41 | } // Predicates = [IsRV64] 42 | 43 | +//===----------------------------------------------------------------------===// 44 | +// Privileged instructions 45 | +//===----------------------------------------------------------------------===// 46 | + 47 | +let isBarrier = 1, isReturn = 1, isTerminator = 1 in { 48 | +def URET : Priv<"uret", 0b0000000> { 49 | + let rd = 0; 50 | + let rs1 = 0; 51 | + let rs2 = 0b00010; 52 | +} 53 | + 54 | +def SRET : Priv<"sret", 0b0001000> { 55 | + let rd = 0; 56 | + let rs1 = 0; 57 | + let rs2 = 0b00010; 58 | +} 59 | + 60 | +def MRET : Priv<"mret", 0b0011000> { 61 | + let rd = 0; 62 | + let rs1 = 0; 63 | + let rs2 = 0b00010; 64 | +} 65 | +} // isBarrier = 1, isReturn = 1, isTerminator = 1 66 | + 67 | +def WFI : Priv<"wfi", 0b0001000> { 68 | + let rd = 0; 69 | + let rs1 = 0; 70 | + let rs2 = 0b00101; 71 | +} 72 | + 73 | +let hasSideEffects = 1, mayLoad = 0, mayStore = 0 in 74 | +def SFENCE_VMA : RVInstR<0b0001001, 0b000, OPC_SYSTEM, (outs), 75 | + (ins GPR:$rs1, GPR:$rs2), 76 | + "sfence.vma", "$rs1, $rs2"> { 77 | + let rd = 0; 78 | +} 79 | + 80 | //===----------------------------------------------------------------------===// 81 | // Pseudo-instructions and codegen patterns 82 | // 83 | diff --git a/test/MC/RISCV/priv-invalid.s b/test/MC/RISCV/priv-invalid.s 84 | new file mode 100644 85 | index 00000000000..96ce291bf6d 86 | --- /dev/null 87 | +++ b/test/MC/RISCV/priv-invalid.s 88 | @@ -0,0 +1,7 @@ 89 | +# RUN: not llvm-mc -triple riscv32 < %s 2>&1 | FileCheck %s 90 | + 91 | +mret 0x10 # CHECK: :[[@LINE]]:6: error: invalid operand for instruction 92 | + 93 | +sfence.vma zero # CHECK: :[[@LINE]]:1: error: too few operands for instruction 94 | + 95 | +sfence.vma a0, 0x10 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction 96 | diff --git a/test/MC/RISCV/priv-valid.s b/test/MC/RISCV/priv-valid.s 97 | new file mode 100644 98 | index 00000000000..e431bf3b088 99 | --- /dev/null 100 | +++ b/test/MC/RISCV/priv-valid.s 101 | @@ -0,0 +1,32 @@ 102 | +# RUN: llvm-mc %s -triple=riscv32 -show-encoding \ 103 | +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 104 | +# RUN: llvm-mc %s -triple=riscv64 -show-encoding \ 105 | +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 106 | +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ 107 | +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s 108 | +# RUN: llvm-mc -filetype=obj -triple riscv64 < %s \ 109 | +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s 110 | + 111 | +# CHECK-INST: uret 112 | +# CHECK: encoding: [0x73,0x00,0x20,0x00] 113 | +uret 114 | + 115 | +# CHECK-INST: sret 116 | +# CHECK: encoding: [0x73,0x00,0x20,0x10] 117 | +sret 118 | + 119 | +# CHECK-INST: mret 120 | +# CHECK: encoding: [0x73,0x00,0x20,0x30] 121 | +mret 122 | + 123 | +# CHECK-INST: wfi 124 | +# CHECK: encoding: [0x73,0x00,0x50,0x10] 125 | +wfi 126 | + 127 | +# CHECK-INST: sfence.vma zero, zero 128 | +# CHECK: encoding: [0x73,0x00,0x00,0x12] 129 | +sfence.vma zero, zero 130 | + 131 | +# CHECK-INST: sfence.vma a0, a1 132 | +# CHECK: encoding: [0x73,0x00,0xb5,0x12] 133 | +sfence.vma a0, a1 134 | -- 135 | 2.16.2 136 | 137 | -------------------------------------------------------------------------------- /0040-RISCV-MC-layer-support-for-the-standard-RV64F-instru.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] MC layer support for the standard RV64F instruction set 4 | extension 5 | 6 | --- 7 | lib/Target/RISCV/RISCVInstrInfoF.td | 22 ++++++++++++++++++++++ 8 | test/MC/RISCV/rv32f-invalid.s | 2 ++ 9 | test/MC/RISCV/rv64f-invalid.s | 9 +++++++++ 10 | test/MC/RISCV/rv64f-valid.s | 37 +++++++++++++++++++++++++++++++++++++ 11 | 4 files changed, 70 insertions(+) 12 | create mode 100644 test/MC/RISCV/rv64f-invalid.s 13 | create mode 100644 test/MC/RISCV/rv64f-valid.s 14 | 15 | diff --git a/lib/Target/RISCV/RISCVInstrInfoF.td b/lib/Target/RISCV/RISCVInstrInfoF.td 16 | index ea2d4175e79..a95d093e7c7 100644 17 | --- a/lib/Target/RISCV/RISCVInstrInfoF.td 18 | +++ b/lib/Target/RISCV/RISCVInstrInfoF.td 19 | @@ -165,3 +165,25 @@ def FMV_W_X : FPUnaryOp_r<0b1111000, 0b000, FPR32, GPR, "fmv.w.x"> { 20 | let rs2 = 0b00000; 21 | } 22 | } // Predicates = [HasStdExtF] 23 | + 24 | +let Predicates = [HasStdExtF, IsRV64] in { 25 | +def FCVT_L_S : FPUnaryOp_r_frm<0b1100000, GPR, FPR32, "fcvt.l.s"> { 26 | + let rs2 = 0b00010; 27 | +} 28 | +def : FPUnaryOpDynFrmAlias; 29 | + 30 | +def FCVT_LU_S : FPUnaryOp_r_frm<0b1100000, GPR, FPR32, "fcvt.lu.s"> { 31 | + let rs2 = 0b00011; 32 | +} 33 | +def : FPUnaryOpDynFrmAlias; 34 | + 35 | +def FCVT_S_L : FPUnaryOp_r_frm<0b1101000, FPR32, GPR, "fcvt.s.l"> { 36 | + let rs2 = 0b00010; 37 | +} 38 | +def : FPUnaryOpDynFrmAlias; 39 | + 40 | +def FCVT_S_LU : FPUnaryOp_r_frm<0b1101000, FPR32, GPR, "fcvt.s.lu"> { 41 | + let rs2 = 0b00011; 42 | +} 43 | +def : FPUnaryOpDynFrmAlias; 44 | +} // Predicates = [HasStdExtF, IsRV64] 45 | diff --git a/test/MC/RISCV/rv32f-invalid.s b/test/MC/RISCV/rv32f-invalid.s 46 | index f22fa7ac5dd..ed9aaed1bca 100644 47 | --- a/test/MC/RISCV/rv32f-invalid.s 48 | +++ b/test/MC/RISCV/rv32f-invalid.s 49 | @@ -30,3 +30,5 @@ fnmsub.s f18, f19, f20, f21, 0b111 # CHECK: :[[@LINE]]:30: error: operand must b 50 | 51 | # Using 'D' instructions for an 'F'-only target 52 | fadd.d ft0, ft1, ft2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled 53 | + 54 | +# Using RV64F instructions for RV32 is tested in rv64f-valid.s 55 | diff --git a/test/MC/RISCV/rv64f-invalid.s b/test/MC/RISCV/rv64f-invalid.s 56 | new file mode 100644 57 | index 00000000000..698da796a7e 58 | --- /dev/null 59 | +++ b/test/MC/RISCV/rv64f-invalid.s 60 | @@ -0,0 +1,9 @@ 61 | +# RUN: not llvm-mc -triple riscv64 -mattr=+f < %s 2>&1 | FileCheck %s 62 | + 63 | +# Integer registers where FP regs are expected 64 | +fcvt.l.s ft0, a0 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction 65 | +fcvt.lu.s ft1, a1 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction 66 | + 67 | +# FP registers where integer regs are expected 68 | +fcvt.s.l a2, ft2 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction 69 | +fcvt.s.lu a3, ft3 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction 70 | diff --git a/test/MC/RISCV/rv64f-valid.s b/test/MC/RISCV/rv64f-valid.s 71 | new file mode 100644 72 | index 00000000000..eda826dfd97 73 | --- /dev/null 74 | +++ b/test/MC/RISCV/rv64f-valid.s 75 | @@ -0,0 +1,37 @@ 76 | +# RUN: llvm-mc %s -triple=riscv64 -mattr=+f -show-encoding \ 77 | +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 78 | +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+f < %s \ 79 | +# RUN: | llvm-objdump -mattr=+f -d - | FileCheck -check-prefix=CHECK-INST %s 80 | +# RUN: not llvm-mc -triple riscv32 -mattr=+f < %s 2>&1 \ 81 | +# RUN: | FileCheck -check-prefix=CHECK-RV32 %s 82 | + 83 | +# CHECK-INST: fcvt.l.s a0, ft0 84 | +# CHECK: encoding: [0x53,0x75,0x20,0xc0] 85 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 86 | +fcvt.l.s a0, ft0 87 | +# CHECK-INST: fcvt.lu.s a1, ft1 88 | +# CHECK: encoding: [0xd3,0xf5,0x30,0xc0] 89 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 90 | +fcvt.lu.s a1, ft1 91 | +# CHECK-INST: fcvt.s.l ft2, a2 92 | +# CHECK: encoding: [0x53,0x71,0x26,0xd0] 93 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 94 | +fcvt.s.l ft2, a2 95 | +# CHECK-INST: fcvt.s.lu ft3, a3 96 | +# CHECK: encoding: [0xd3,0xf1,0x36,0xd0] 97 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 98 | +fcvt.s.lu ft3, a3 99 | + 100 | +# Rounding modes 101 | +# CHECK-INST: fcvt.l.s a4, ft4, rne 102 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 103 | +fcvt.l.s a4, ft4, rne 104 | +# CHECK-INST: fcvt.lu.s a5, ft5, rtz 105 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 106 | +fcvt.lu.s a5, ft5, rtz 107 | +# CHECK-INST: fcvt.s.l ft6, a6, rdn 108 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 109 | +fcvt.s.l ft6, a6, rdn 110 | +# CHECK-INST: fcvt.s.lu ft7, a7, rup 111 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 112 | +fcvt.s.lu ft7, a7, rup 113 | -- 114 | 2.16.2 115 | 116 | -------------------------------------------------------------------------------- /0047-RISCV-Initial-support-for-emitting-call-frame-inform.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Initial support for emitting call frame information (needs 4 | testing) 5 | 6 | This patch tests that appropriate directives are emitted, but I haven't done 7 | an end-to-end test using gdb. 8 | --- 9 | lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp | 2 ++ 10 | .../RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp | 6 +++++- 11 | lib/Target/RISCV/RISCVFrameLowering.cpp | 21 +++++++++++++++++++ 12 | test/CodeGen/RISCV/cfi-info.ll | 24 ++++++++++++++++++++++ 13 | 4 files changed, 52 insertions(+), 1 deletion(-) 14 | create mode 100644 test/CodeGen/RISCV/cfi-info.ll 15 | 16 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp 17 | index d622911e92c..9f806dc1a49 100644 18 | --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp 19 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp 20 | @@ -22,4 +22,6 @@ RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) { 21 | CommentString = "#"; 22 | AlignmentIsInBytes = false; 23 | SupportsDebugInformation = true; 24 | + ExceptionsType = ExceptionHandling::DwarfCFI; 25 | + DwarfRegNumForCFI = true; 26 | } 27 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp 28 | index 45de976ec6c..f9a69826e10 100644 29 | --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp 30 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp 31 | @@ -48,7 +48,11 @@ static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) { 32 | 33 | static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI, 34 | const Triple &TT) { 35 | - return new RISCVMCAsmInfo(TT); 36 | + MCAsmInfo *MAI = new RISCVMCAsmInfo(TT); 37 | + // Initial state of the frame pointer is SP. 38 | + unsigned Reg = MRI.getDwarfRegNum(RISCV::X2, true); 39 | + MAI->addInitialFrameState(MCCFIInstruction::createDefCfa(nullptr, Reg, 0)); 40 | + return MAI; 41 | } 42 | 43 | static MCSubtargetInfo *createRISCVMCSubtargetInfo(const Triple &TT, 44 | diff --git a/lib/Target/RISCV/RISCVFrameLowering.cpp b/lib/Target/RISCV/RISCVFrameLowering.cpp 45 | index 33703f5ec20..324ae8f2f3b 100644 46 | --- a/lib/Target/RISCV/RISCVFrameLowering.cpp 47 | +++ b/lib/Target/RISCV/RISCVFrameLowering.cpp 48 | @@ -17,6 +17,7 @@ 49 | #include "llvm/CodeGen/MachineFrameInfo.h" 50 | #include "llvm/CodeGen/MachineFunction.h" 51 | #include "llvm/CodeGen/MachineInstrBuilder.h" 52 | +#include "llvm/CodeGen/MachineModuleInfo.h" 53 | #include "llvm/CodeGen/MachineRegisterInfo.h" 54 | #include "llvm/CodeGen/RegisterScavenging.h" 55 | 56 | @@ -113,6 +114,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, 57 | MachineFrameInfo &MFI = MF.getFrameInfo(); 58 | auto *RVFI = MF.getInfo(); 59 | MachineBasicBlock::iterator MBBI = MBB.begin(); 60 | + const RISCVInstrInfo *TII = STI.getInstrInfo(); 61 | 62 | unsigned FPReg = getFPReg(STI); 63 | unsigned SPReg = getSPReg(STI); 64 | @@ -148,6 +150,25 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, 65 | if (hasFP(MF)) 66 | adjustReg(MBB, MBBI, DL, FPReg, SPReg, 67 | StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup); 68 | + 69 | + // Emit CFI records: 70 | + const MCRegisterInfo *MRI = MF.getMMI().getContext().getRegisterInfo(); 71 | + // .cfi_def_cfa_offset -StackSize 72 | + unsigned CFIIndex = MF.addFrameInst( 73 | + MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); 74 | + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 75 | + .addCFIIndex(CFIIndex) 76 | + .setMIFlags(MachineInstr::FrameSetup); 77 | + // .cfi_def_cfa_register DwarfRegNum 78 | + for (const auto &Entry : CSI) { 79 | + unsigned Reg = Entry.getReg(); 80 | + int FI = Entry.getFrameIdx(); 81 | + CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( 82 | + nullptr, MRI->getDwarfRegNum(Reg, true), MFI.getObjectOffset(FI))); 83 | + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 84 | + .addCFIIndex(CFIIndex) 85 | + .setMIFlags(MachineInstr::FrameSetup); 86 | + } 87 | } 88 | 89 | void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, 90 | diff --git a/test/CodeGen/RISCV/cfi-info.ll b/test/CodeGen/RISCV/cfi-info.ll 91 | new file mode 100644 92 | index 00000000000..32d246380ac 93 | --- /dev/null 94 | +++ b/test/CodeGen/RISCV/cfi-info.ll 95 | @@ -0,0 +1,24 @@ 96 | +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s | FileCheck %s 97 | + 98 | +define i32 @callee(i32 %a, i64 %b, i32 %c, i32 %d, double %e) { 99 | +; CHECK-LABEL: callee: 100 | +; CHECK: addi sp, sp, -32 101 | +; CHECK: sw ra, 28(sp) 102 | +; CHECK: sw s1, 24(sp) 103 | +; CHECK: sw s2, 20(sp) 104 | +; CHECK: sw s3, 16(sp) 105 | +; CHECK: sw s4, 12(sp) 106 | +; CHECK: .cfi_def_cfa_offset 32 107 | +; CHECK: .cfi_offset 1, -4 108 | +; CHECK: .cfi_offset 9, -8 109 | +; CHECK: .cfi_offset 18, -12 110 | +; CHECK: .cfi_offset 19, -16 111 | +; CHECK: .cfi_offset 20, -20 112 | + %b_trunc = trunc i64 %b to i32 113 | + %e_fptosi = fptosi double %e to i32 114 | + %1 = add i32 %a, %b_trunc 115 | + %2 = add i32 %1, %c 116 | + %3 = add i32 %2, %d 117 | + %4 = add i32 %3, %e_fptosi 118 | + ret i32 %4 119 | +} 120 | -- 121 | 2.16.2 122 | 123 | -------------------------------------------------------------------------------- /0041-RISCV-MC-layer-support-for-the-standard-RV64D-instru.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] MC layer support for the standard RV64D instruction set 4 | extension 5 | 6 | --- 7 | lib/Target/RISCV/RISCVInstrInfoD.td | 30 +++++++++++++++++++++++ 8 | test/MC/RISCV/rv64d-invalid.s | 11 +++++++++ 9 | test/MC/RISCV/rv64d-valid.s | 49 +++++++++++++++++++++++++++++++++++++ 10 | 3 files changed, 90 insertions(+) 11 | create mode 100644 test/MC/RISCV/rv64d-invalid.s 12 | create mode 100644 test/MC/RISCV/rv64d-valid.s 13 | 14 | diff --git a/lib/Target/RISCV/RISCVInstrInfoD.td b/lib/Target/RISCV/RISCVInstrInfoD.td 15 | index aa194320d99..8a78e372e8b 100644 16 | --- a/lib/Target/RISCV/RISCVInstrInfoD.td 17 | +++ b/lib/Target/RISCV/RISCVInstrInfoD.td 18 | @@ -129,3 +129,33 @@ def FCVT_D_WU : FPUnaryOp_r<0b1101001, 0b000, FPR64, GPR, "fcvt.d.wu"> { 19 | let rs2 = 0b00001; 20 | } 21 | } // Predicates = [HasStdExtD] 22 | + 23 | +let Predicates = [HasStdExtD, IsRV64] in { 24 | +def FCVT_L_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.l.d"> { 25 | + let rs2 = 0b00010; 26 | +} 27 | +def : FPUnaryOpDynFrmAlias; 28 | + 29 | +def FCVT_LU_D : FPUnaryOp_r_frm<0b1100001, GPR, FPR64, "fcvt.lu.d"> { 30 | + let rs2 = 0b00011; 31 | +} 32 | +def : FPUnaryOpDynFrmAlias; 33 | + 34 | +def FMV_X_D : FPUnaryOp_r<0b1110001, 0b000, GPR, FPR64, "fmv.x.d"> { 35 | + let rs2 = 0b00000; 36 | +} 37 | + 38 | +def FCVT_D_L : FPUnaryOp_r_frm<0b1101001, FPR64, GPR, "fcvt.d.l"> { 39 | + let rs2 = 0b00010; 40 | +} 41 | +def : FPUnaryOpDynFrmAlias; 42 | + 43 | +def FCVT_D_LU : FPUnaryOp_r_frm<0b1101001, FPR64, GPR, "fcvt.d.lu"> { 44 | + let rs2 = 0b00011; 45 | +} 46 | +def : FPUnaryOpDynFrmAlias; 47 | + 48 | +def FMV_D_X : FPUnaryOp_r<0b1111001, 0b000, FPR64, GPR, "fmv.d.x"> { 49 | + let rs2 = 0b00000; 50 | +} 51 | +} // Predicates = [HasStdExtD, IsRV64] 52 | diff --git a/test/MC/RISCV/rv64d-invalid.s b/test/MC/RISCV/rv64d-invalid.s 53 | new file mode 100644 54 | index 00000000000..0f508aafd9b 55 | --- /dev/null 56 | +++ b/test/MC/RISCV/rv64d-invalid.s 57 | @@ -0,0 +1,11 @@ 58 | +# RUN: not llvm-mc -triple riscv64 -mattr=+d < %s 2>&1 | FileCheck %s 59 | + 60 | +# Integer registers where FP regs are expected 61 | +fcvt.l.d ft0, a0 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction 62 | +fcvt.lu.d ft1, a1 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction 63 | +fmv.x.d ft2, a2 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction 64 | + 65 | +# FP registers where integer regs are expected 66 | +fcvt.d.l a3, ft3 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction 67 | +fcvt.d.lu a4, ft4 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction 68 | +fmv.d.x a5, ft5 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction 69 | diff --git a/test/MC/RISCV/rv64d-valid.s b/test/MC/RISCV/rv64d-valid.s 70 | new file mode 100644 71 | index 00000000000..e24fd250d43 72 | --- /dev/null 73 | +++ b/test/MC/RISCV/rv64d-valid.s 74 | @@ -0,0 +1,49 @@ 75 | +# RUN: llvm-mc %s -triple=riscv64 -mattr=+d -show-encoding \ 76 | +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 77 | +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+d < %s \ 78 | +# RUN: | llvm-objdump -mattr=+d -d - | FileCheck -check-prefix=CHECK-INST %s 79 | +# RUN: not llvm-mc -triple riscv32 -mattr=+d < %s 2>&1 \ 80 | +# RUN: | FileCheck -check-prefix=CHECK-RV32 %s 81 | + 82 | +# CHECK-INST: fcvt.l.d a0, ft0 83 | +# CHECK: encoding: [0x53,0x75,0x20,0xc2] 84 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 85 | +fcvt.l.d a0, ft0 86 | +# CHECK-INST: fcvt.lu.d a1, ft1 87 | +# CHECK: encoding: [0xd3,0xf5,0x30,0xc2] 88 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 89 | +fcvt.lu.d a1, ft1 90 | +# CHECK-INST: fmv.x.d a2, ft2 91 | +# CHECK: encoding: [0x53,0x06,0x01,0xe2] 92 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 93 | +fmv.x.d a2, ft2 94 | +# CHECK-INST: fcvt.d.l ft3, a3 95 | +# CHECK: encoding: [0xd3,0xf1,0x26,0xd2] 96 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 97 | +fcvt.d.l ft3, a3 98 | +# CHECK-INST: fcvt.d.lu ft4, a4 99 | +# CHECK: encoding: [0x53,0x72,0x37,0xd2] 100 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 101 | +fcvt.d.lu ft4, a4 102 | +# CHECK-INST: fmv.d.x ft5, a5 103 | +# CHECK: encoding: [0xd3,0x82,0x07,0xf2] 104 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 105 | +fmv.d.x ft5, a5 106 | + 107 | +# Rounding modes 108 | +# CHECK-INST: fcvt.d.l ft3, a3, rne 109 | +# CHECK: encoding: [0xd3,0x81,0x26,0xd2] 110 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 111 | +fcvt.d.l ft3, a3, rne 112 | +# CHECK-INST: fcvt.d.lu ft4, a4, rtz 113 | +# CHECK: encoding: [0x53,0x12,0x37,0xd2] 114 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 115 | +fcvt.d.lu ft4, a4, rtz 116 | +# CHECK-INST: fcvt.l.d a0, ft0, rdn 117 | +# CHECK: encoding: [0x53,0x25,0x20,0xc2] 118 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 119 | +fcvt.l.d a0, ft0, rdn 120 | +# CHECK-INST: fcvt.lu.d a1, ft1, rup 121 | +# CHECK: encoding: [0xd3,0xb5,0x30,0xc2] 122 | +# CHECK-RV32: :[[@LINE+1]]:1: error: instruction use requires an option to be enabled 123 | +fcvt.lu.d a1, ft1, rup 124 | -- 125 | 2.16.2 126 | 127 | -------------------------------------------------------------------------------- /docs/01-intro-and-building-llvm.mkd: -------------------------------------------------------------------------------- 1 | # A step-by-step guide to the RISC-V LLVM backend 2 | 3 | ## Introduction 4 | Creating a new compiler backend can seem like an insurmountable challenge at 5 | times. As well as the challenges of integrating your code into a complex 6 | compiler toolchain, you're often contending with unstable assemblers, linkers, 7 | runtime libraries and even simulators. In my view, taking an incremental 8 | approach to backend development is the only way to successfully battle this 9 | complexity. Copying code from another backend and modifying it until it 10 | produces plausible output allows rapid initial progress, but isolating and 11 | debugging issues can be incredibly difficult. 12 | 13 | This document describes the approach taken for the implementation of the 14 | RISC-V backend. I hope this will serve as a useful reference for prospective 15 | developers of any LLVM backend. 16 | 17 | Please note: this documentation is a work in progress. A HTML-rendered "v1" 18 | will be posted on lowrisc.org soon. 19 | 20 | ## Building LLVM 21 | Before doing anything else, it's worth ensuring you can check out and build an 22 | unmodified LLVM. 23 | 24 | git clone https://git.llvm.org/git/llvm.git 25 | cd llvm 26 | 27 | These instructions give a very condensed recipe for building LLVM. The 28 | [official documentation](http://llvm.org/docs/GettingStarted.html) has more 29 | detail if necessary. 30 | 31 | First, ensure you have necessary dependencies. The LLVM documentation has a 32 | more complete listing, but ensuring you have ninja, CMake, and a recent host 33 | compiler (e.g. Clang) is a good starting point: 34 | 35 | sudo apt-get install clang ninja cmake 36 | 37 | LLVM development involves a huge number of incremental rebuilds (i.e. 38 | compiling after making a small change). Choosing compiler options that help 39 | reduce the time this takes is really useful for productivity. This [blog 40 | post](https://blogs.s-osg.org/an-introduction-to-accelerating-your-build-with-clang/) 41 | provides some useful guidance. 42 | 43 | mkdir build 44 | cd build 45 | cmake -G Ninja -DCMAKE_BUILD_TYPE="Debug" \ 46 | -DBUILD_SHARED_LIBS=True -DLLVM_USE_SPLIT_DWARF=True \ 47 | -DLLVM_OPTIMIZED_TABLEGEN=True \ 48 | -DLLVM_BUILD_TESTS=True \ 49 | -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ 50 | -DLLVM_TARGETS_TO_BUILD="X86" ../ 51 | cmake --build . 52 | 53 | To explain some of these options: 54 | * `cmake -G Ninja` will cause CMake to use the 55 | [Ninja](https://martine.github.io/ninja/) build system and generate a 56 | build.ninja file rather than Makefiles 57 | * `-DBUILD_SHARED_LIBS=True` and `-DLLVM_USE_SPLIT_DWARF=True` ultimately 58 | reduce incremental build times by reducing file I/O 59 | * `-DLLVM_TARGETS_TO_BUILD="X86"` specifies that only the X86 target will be 60 | built. This is one way of speeding up the build. 61 | * `-DCMAKE_BUILD_TYPE="Debug"` means a debug build will be produced, which has 62 | assertions and backtraces enabled. The binaries will be larger and slower than 63 | a release build. 64 | * `-DLLVM_OPTIMIZED_TABLEGEN=True` will cause a release binary of tblgen to 65 | be built and used. This can decrease build time for debug builds. 66 | * `-DLLVM_BUILD_TESTS=True` as the option name suggests will cause unit tests 67 | to be built by default. 68 | * With `-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++`, the system 69 | Clang compiler will be used. This is typically faster than GCC and can 70 | have better error messages. 71 | 72 | ## Running the LLVM test suite 73 | 74 | LLVM has an [extensive test 75 | infrastructure](http://llvm.org/docs/TestingGuide.html). Before getting stuck 76 | into coding, it's worth familiarising yourself with the basics and being sure 77 | you're able to invoke the test suite. 78 | 79 | LLVM's regression tests live in the `test/` and `unittest/` subdirectories. 80 | You can invoke all these tests using the `llvm-lit` tool. From the build dir, 81 | execute `./bin/llvm-lit test -s`. This will execute all tests and present a 82 | nice progress bar. As you can verify for yourself with `./bin/llvm-lit 83 | --show-suites test` the lit tool discovers both sets of tests. Although the 84 | full suite runs reasonably quickly, it can also be useful to run only a subset 85 | of tests. The `--filter` parameter allows you to specify a regular expression 86 | that will be used to select the tests to be run. e.g. `./bin/llvm-lit -s 87 | --filter 'ScalarEvolution' test` will run only the tests with ScalarEvolution 88 | in their name. Another useful parameter to help speed up the edit-compile-test 89 | cycle is `-i` which will run modified and recently failed tests first. 90 | Frequently, this is what you want in order to rapidly determine whether your 91 | change fixed a previously failing test or your recently modified tests still 92 | pass. 93 | 94 | ## Setting up your repo 95 | 96 | Now you can build LLVM and run the test suites, the only remaining task is to 97 | set up the Git repository so you can commit changes and easily pull in changes 98 | from upstream. There are many ways of organising this, but the following 99 | describes the approach I've found most helpful. 100 | 101 | First, rename 'origin' to 'upstream' 102 | 103 | git remote rename origin upstream 104 | git config --unset branch.master.remote 105 | 106 | Then set up a new 'origin', with a git remote that will host your code (e.g. a 107 | repository in a GitHub account). 108 | 109 | git remote add origin your@gitrepo.org:here.git 110 | git push -u origin master 111 | 112 | In future checkouts from this new 'origin', you will need to explicitly add 113 | the upstream remote: 114 | 115 | git remote add upstream http://llvm.org/git/llvm.git 116 | 117 | To rebase on top changes from upstream at any time: 118 | 119 | git fetch upstream 120 | git rebase upstream/master 121 | -------------------------------------------------------------------------------- /0055-RISCV-Add-codegen-support-for-RV32D-floating-point-a.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Add codegen support for RV32D floating point arithmetic 4 | operations 5 | 6 | --- 7 | lib/Target/RISCV/RISCVISelLowering.cpp | 5 ++ 8 | lib/Target/RISCV/RISCVInstrInfoD.td | 29 +++++++++++ 9 | test/CodeGen/RISCV/double-arith.ll | 91 ++++++++++++++++++++++++++++++++++ 10 | 3 files changed, 125 insertions(+) 11 | 12 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 13 | index 44a2538a665..4d93f1f723e 100644 14 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | @@ -121,6 +121,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, 17 | setOperationAction(ISD::BR_CC, MVT::f32, Expand); 18 | } 19 | 20 | + if (Subtarget.hasStdExtD()) { 21 | + setOperationAction(ISD::FMINNUM, MVT::f64, Legal); 22 | + setOperationAction(ISD::FMAXNUM, MVT::f64, Legal); 23 | + } 24 | + 25 | setOperationAction(ISD::GlobalAddress, XLenVT, Custom); 26 | setOperationAction(ISD::BlockAddress, XLenVT, Custom); 27 | setOperationAction(ISD::ConstantPool, XLenVT, Custom); 28 | diff --git a/lib/Target/RISCV/RISCVInstrInfoD.td b/lib/Target/RISCV/RISCVInstrInfoD.td 29 | index 1d29a7c086b..b6b47c97e85 100644 30 | --- a/lib/Target/RISCV/RISCVInstrInfoD.td 31 | +++ b/lib/Target/RISCV/RISCVInstrInfoD.td 32 | @@ -164,6 +164,9 @@ def FMV_D_X : FPUnaryOp_r<0b1111001, 0b000, FPR64, GPR, "fmv.d.x"> { 33 | // Pseudo-instructions and codegen patterns 34 | //===----------------------------------------------------------------------===// 35 | 36 | +class PatFpr64Fpr64 37 | + : Pat<(OpNode FPR64:$rs1, FPR64:$rs2), (Inst $rs1, $rs2)>; 38 | + 39 | class PatFpr64Fpr64DynFrm 40 | : Pat<(OpNode FPR64:$rs1, FPR64:$rs2), (Inst $rs1, $rs2, 0b111)>; 41 | 42 | @@ -172,5 +175,31 @@ let Predicates = [HasStdExtD] in { 43 | /// Float arithmetic operations 44 | 45 | def : PatFpr64Fpr64DynFrm; 46 | +def : PatFpr64Fpr64DynFrm; 47 | +def : PatFpr64Fpr64DynFrm; 48 | +def : PatFpr64Fpr64DynFrm; 49 | + 50 | +def : Pat<(fsqrt FPR64:$rs1), (FSQRT_D FPR64:$rs1, 0b111)>; 51 | + 52 | +def : Pat<(fneg FPR64:$rs1), (FSGNJN_D $rs1, $rs1)>; 53 | +def : Pat<(fabs FPR64:$rs1), (FSGNJX_D $rs1, $rs1)>; 54 | + 55 | +def : PatFpr64Fpr64; 56 | +def : Pat<(fcopysign FPR64:$rs1, (fneg FPR64:$rs2)), (FSGNJN_D $rs1, $rs2)>; 57 | + 58 | +// The RISC-V 2.2 user-level ISA spec defines fmin and fmax as returning the 59 | +// canonical NaN when giving a signaling NaN. This doesn't match the LLVM 60 | +// behaviour (see https://bugs.llvm.org/show_bug.cgi?id=27363). However, the 61 | +// draft 2.3 ISA spec changes the definition of fmin and fmax in a way that 62 | +// matches LLVM's fminnum and fmaxnum 63 | +// . 64 | +def : PatFpr64Fpr64; 65 | +def : PatFpr64Fpr64; 66 | + 67 | +/// Setcc 68 | + 69 | +def : PatFpr64Fpr64; 70 | +def : PatFpr64Fpr64; 71 | +def : PatFpr64Fpr64; 72 | 73 | } // Predicates = [HasStdExtD] 74 | diff --git a/test/CodeGen/RISCV/double-arith.ll b/test/CodeGen/RISCV/double-arith.ll 75 | index f759b4d3b97..cc8ed150b4f 100644 76 | --- a/test/CodeGen/RISCV/double-arith.ll 77 | +++ b/test/CodeGen/RISCV/double-arith.ll 78 | @@ -21,3 +21,94 @@ define double @fadd_d(double %a, double %b) nounwind { 79 | %1 = fadd double %a, %b 80 | ret double %1 81 | } 82 | + 83 | +define double @fsub_d(double %a, double %b) nounwind { 84 | + %1 = fsub double %a, %b 85 | + ret double %1 86 | +} 87 | + 88 | +define double @fmul_d(double %a, double %b) nounwind { 89 | + %1 = fmul double %a, %b 90 | + ret double %1 91 | +} 92 | + 93 | +define double @fdiv_d(double %a, double %b) nounwind { 94 | + %1 = fdiv double %a, %b 95 | + ret double %1 96 | +} 97 | + 98 | +declare double @llvm.sqrt.f32(double) 99 | + 100 | +define double @fsqrt_d(double %a) nounwind { 101 | + %1 = call double @llvm.sqrt.f32(double %a) 102 | + ret double %1 103 | +} 104 | + 105 | +declare double @llvm.copysign.f32(double, double) 106 | + 107 | +define double @fsgnj_d(double %a, double %b) nounwind { 108 | + %1 = call double @llvm.copysign.f32(double %a, double %b) 109 | + ret double %1 110 | +} 111 | + 112 | +define double @fneg_d(double %a) nounwind { 113 | +; TODO: doesn't test the fneg selection pattern because 114 | +; DAGCombiner::visitBITCAST will generate a xor on the incoming integer 115 | +; argument 116 | + %1 = fsub double -0.0, %a 117 | + ret double %1 118 | +} 119 | + 120 | +define double @fsgnjn_d(double %a, double %b) nounwind { 121 | +; TODO: fsgnjn.s isn't selected because DAGCombiner::visitBITCAST will convert 122 | +; (bitconvert (fneg x)) to a xor 123 | + %1 = fsub double -0.0, %b 124 | + %2 = call double @llvm.copysign.f32(double %a, double %1) 125 | + ret double %2 126 | +} 127 | + 128 | +declare double @llvm.fabs.f32(double) 129 | + 130 | +define double @fabs_d(double %a) nounwind { 131 | +; TODO: doesn't test the fabs selection pattern because 132 | +; DAGCombiner::visitBITCAST will generate an and on the incoming integer 133 | +; argument 134 | + %1 = call double @llvm.fabs.f32(double %a) 135 | + ret double %1 136 | +} 137 | + 138 | +; TODO: implement a test for fsgnjx 139 | +;define double @fsgnjx_d(double %a, double %b) nounwind { 140 | +;} 141 | + 142 | +declare double @llvm.minnum.f32(double, double) 143 | + 144 | +define double @fmin_d(double %a, double %b) nounwind { 145 | + %1 = call double @llvm.minnum.f32(double %a, double %b) 146 | + ret double %1 147 | +} 148 | + 149 | +declare double @llvm.maxnum.f32(double, double) 150 | + 151 | +define double @fmax_d(double %a, double %b) nounwind { 152 | + %1 = call double @llvm.maxnum.f32(double %a, double %b) 153 | + ret double %1 154 | +} 155 | + 156 | +define i32 @feq_d(double %a, double %b) nounwind { 157 | + %1 = fcmp oeq double %a, %b 158 | + %2 = zext i1 %1 to i32 159 | + ret i32 %2 160 | +} 161 | + 162 | +define i32 @flt_d(double %a, double %b) nounwind { 163 | + %1 = fcmp olt double %a, %b 164 | + %2 = zext i1 %1 to i32 165 | + ret i32 %2 166 | +} 167 | + 168 | +define i32 @fle_d(double %a, double %b) nounwind { 169 | + %1 = fcmp ole double %a, %b 170 | + %2 = zext i1 %1 to i32 171 | + ret i32 %2 172 | +} 173 | -- 174 | 2.16.2 175 | 176 | -------------------------------------------------------------------------------- /docs/07-initial-codegen.mkd: -------------------------------------------------------------------------------- 1 | # Initial steps towards codegen support 2 | 3 | The next implementation task is to add support for basic code generation. 4 | There's a reasonable amount of boilerplate code needed to do this, which means 5 | most of the difficulty comes from identifying the minimal set of needed 6 | support code. A truly minimal starting point would be to implement codegen for 7 | a function with no argument that returns void. However, the incremental 8 | difficulty of supporting code-gen for simple arithmetic operations is very low 9 | and doing that extra work gives much greater assurance that the implementation 10 | is correct. Therefore, start by implementing support for the RV32I ALU 11 | operations. 12 | 13 | ## An overview of newly added support code 14 | 15 | * RISCVAsmPrinter and RISCVMCInstLower 16 | * Responsible for converting a MachineInstr to an MCInst. This is handled by 17 | `llvm::LowerRISCVMachineInstrToMCInst` which simply sets the opcode and adds 18 | corresponding MCOperands for register or immediate operands for the input 19 | MachineInstr. 20 | * RISCVInstrInfo 21 | * At this stage, requires no hand-written code. RISCVInstrInfo.{h,cpp} 22 | include RISCVGenInstrInfo.inc which is generated from RISCVInstrInfo.td. 23 | This defines an enum containing all defined RISCV instructions, e.g. 24 | `RISCV::ADDI`. 25 | * RISCVRegisterInfo 26 | * Just like RISCVInstrInfo, this is heavily reliant on table-generated code. 27 | * We need to pass the return address register to the RISCVGenRegisterInfo 28 | constructor. 29 | * getReservedRegs must indicate all registers which should be considered 30 | reserved and so ignored by the register allocator. 31 | * getFrameRegister simply returns the register used for frame indices. Given 32 | we are yet to implement frame pointer elimination, always return RISCV::X8. 33 | * eliminateFrameIndex needs to be present, but for now it's just a stub that 34 | calls `report_fatal_error`. 35 | * RISCVSubtarget 36 | * Contains a number of accessors for instances of the classes we've 37 | implemented. e.g. `getFrameLowering`, `getInstrInfo`, `getRegisterInfo`, 38 | `getTargetLowering` and so on. 39 | * RISCVPassConfig 40 | * RISCVISelDAGToDAG 41 | * This is responsible for selecting an appropriate RISC-V instruction for 42 | each SelectionDAG node. `RISCVDAGToDAGISel::Select` is the main entry point 43 | for this process, which simply calls the tablegenerated `SelectCode` 44 | function. See below for details on specifying patterns which control this 45 | process. 46 | * RISCVISelLowering 47 | * Ultimately lowers LLVM code into the SelectionDAG. The majority of the 48 | code which performs this transformation is target independent, and we just 49 | need to implement a few hooks to influence this process. See below for more 50 | details. 51 | 52 | ## Specifying patterns in RISCVInstrInfo.td 53 | 54 | The RISC-V backend structures RISCVInstrInfo.td so instruction selection 55 | patterns are specified separately from the instruction definitions. A pattern 56 | for add can be trivially specified: 57 | 58 | def : Pat<(add GPR:$rs1, GPR:$rs2), (ADD GPR:$rs1, GPR:$rs2)>; 59 | 60 | The first parameter to Pat specifies the SelectionDAG node to match. See 61 | `include/llvm/Target/TargetSelectionDAG.td` for a full listing of such nodes. 62 | The second parameter specifies the RISC-V instruction(s) to lower it to. 63 | 64 | The register-immediate form of add (`addi`) can be matched as below: 65 | 66 | def : Pat<(add GPR:$rs1, simm12:$imm12), (ADDI GPR:$rs1, simm12:$imm12)>; 67 | 68 | Note that to lower ADDI we are matching the same SelectionDAG node (`add`) but 69 | with different constraints - the immediate operand. The LLVM SelectionDAG 70 | infrastructure will handle checking the preconditions for each pattern. For 71 | the above pattern to work, `simm12` must also be constrained in a way that can 72 | be understood by SelectionDAG. We make it derive from `ImmLeaf` in addition to 73 | `Operand`, as it was before: 74 | 75 | def simm12 : Operand, ImmLeaf(Imm);}]> { 76 | ... 77 | } 78 | 79 | ## RISCVISelLowering 80 | 81 | The constructor calls several helper functions which influence lowering. 82 | Importantly, `addRegisterClass(XLenVT, &RISCV::GPRRegClass);` will ensure that 83 | `XLenVT` (`i32` for RV32) is considered a legal type. Future patches will add 84 | more code, for instance specifying which operations should be expanded into 85 | semantic equivalents rather than attempting to lower them directly. 86 | 87 | The two key methods to implement at this stage are `LowerFormalArguments` and 88 | `LowerReturn`. The former will determine which registers each argument is 89 | passed in, and create an appropriate virtual register. `LowerReturn` will copy 90 | the return value into the register appropriate for the target calling 91 | convention. 92 | 93 | 94 | 95 | ## Specifying the calling convention 96 | 97 | At this stage, we won't attempt to support the full detail of the [RISC-V 98 | calling 99 | convention](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md). 100 | Instead, specify the basic register assignments in RISCVCallingConv.td: 101 | 102 | // RISCV 32-bit C return-value convention. 103 | def RetCC_RISCV32 : CallingConv<[CCIfType<[i32], CCAssignToReg<[X10, X11]>>]>; 104 | 105 | // RISCV 32-bit C Calling convention. 106 | def CC_RISCV32 : CallingConv<[ 107 | // Promote i8/i16 args to i32 108 | CCIfType<[ i8, i16 ], CCPromoteToType>, 109 | 110 | // All arguments get passed in integer registers if there is space. 111 | CCIfType<[i32], CCAssignToReg<[ X10, X11, X12, X13, X14, X15, X16, X17]>>, 112 | 113 | // Could be assigned to the stack in 8-byte aligned units, but unsupported 114 | CCAssignToStack<8, 8> 115 | ]>; 116 | 117 | This will generate `CC_RISCV32` and `RetCC_RISCV32` functions which you can make us of in RISCVISelLowering.cpp. 118 | 119 | Also list the callee-saved registers: 120 | 121 | def CSR : CalleeSavedRegs<(add X1, X3, X4, X8, X9, (sequence "X%u", 18, 27))>; 122 | 123 | ## Specifying tests 124 | 125 | Tests for the MC layer were written in `test/MC/RISCV` and utilised 126 | `FileCheck`. You can write tests using `FileCheck` again for codegen, placing 127 | them in `test/CodeGen/RISCV`. These tests take the form of simple functions 128 | written in LLVM IR, and include checks on the generated assembly after 129 | compilation with `llc`. I strongly recommend the use of 130 | `update_llc_test_checks.py` to automate the generation of check lines. 131 | 132 | -------------------------------------------------------------------------------- /0033-RISCV-MC-layer-support-for-the-standard-RV32M-instru.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] MC layer support for the standard RV32M instruction set 4 | extension 5 | 6 | --- 7 | lib/Target/RISCV/RISCV.td | 14 ++++++++++---- 8 | lib/Target/RISCV/RISCVInstrInfo.td | 6 ++++++ 9 | lib/Target/RISCV/RISCVInstrInfoM.td | 28 ++++++++++++++++++++++++++++ 10 | lib/Target/RISCV/RISCVSubtarget.h | 2 ++ 11 | test/MC/RISCV/rv32i-invalid.s | 3 +++ 12 | test/MC/RISCV/rv32m-valid.s | 33 +++++++++++++++++++++++++++++++++ 13 | 6 files changed, 82 insertions(+), 4 deletions(-) 14 | create mode 100644 lib/Target/RISCV/RISCVInstrInfoM.td 15 | create mode 100644 test/MC/RISCV/rv32m-valid.s 16 | 17 | diff --git a/lib/Target/RISCV/RISCV.td b/lib/Target/RISCV/RISCV.td 18 | index da919acad36..6fc54a517dd 100644 19 | --- a/lib/Target/RISCV/RISCV.td 20 | +++ b/lib/Target/RISCV/RISCV.td 21 | @@ -13,11 +13,17 @@ include "llvm/Target/Target.td" 22 | // RISC-V subtarget features and instruction predicates. 23 | //===----------------------------------------------------------------------===// 24 | 25 | -def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true", 26 | - "Implements RV64">; 27 | +def FeatureStdExtM 28 | + : SubtargetFeature<"m", "HasStdExtM", "true", 29 | + "'M' (Integer Multiplication and Division)">; 30 | +def HasStdExtM : Predicate<"Subtarget->hasStdExtM()">, 31 | + AssemblerPredicate<"FeatureStdExtM">; 32 | 33 | -def RV64 : HwMode<"+64bit">; 34 | -def RV32 : HwMode<"-64bit">; 35 | +def Feature64Bit 36 | + : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; 37 | + 38 | +def RV64 : HwMode<"+64bit">; 39 | +def RV32 : HwMode<"-64bit">; 40 | 41 | //===----------------------------------------------------------------------===// 42 | // Registers, calling conventions, instruction descriptions. 43 | diff --git a/lib/Target/RISCV/RISCVInstrInfo.td b/lib/Target/RISCV/RISCVInstrInfo.td 44 | index 3031a77d0fe..0ea13f7c1d5 100644 45 | --- a/lib/Target/RISCV/RISCVInstrInfo.td 46 | +++ b/lib/Target/RISCV/RISCVInstrInfo.td 47 | @@ -461,3 +461,9 @@ def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), 48 | def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), 49 | [(CallSeqEnd timm:$amt1, timm:$amt2)]>; 50 | } // Defs = [X2], Uses = [X2] 51 | + 52 | +//===----------------------------------------------------------------------===// 53 | +// Standard extensions 54 | +//===----------------------------------------------------------------------===// 55 | + 56 | +include "RISCVInstrInfoM.td" 57 | diff --git a/lib/Target/RISCV/RISCVInstrInfoM.td b/lib/Target/RISCV/RISCVInstrInfoM.td 58 | new file mode 100644 59 | index 00000000000..a253c1eb811 60 | --- /dev/null 61 | +++ b/lib/Target/RISCV/RISCVInstrInfoM.td 62 | @@ -0,0 +1,28 @@ 63 | +//===-- RISCVInstrInfoM.td - RISC-V 'M' instructions -------*- tablegen -*-===// 64 | +// 65 | +// The LLVM Compiler Infrastructure 66 | +// 67 | +// This file is distributed under the University of Illinois Open Source 68 | +// License. See LICENSE.TXT for details. 69 | +// 70 | +//===----------------------------------------------------------------------===// 71 | +// 72 | +// This file describes the RISC-V instructions from the standard 'M', Integer 73 | +// Multiplication and Division instruction set extension. 74 | +// 75 | +//===----------------------------------------------------------------------===// 76 | + 77 | +//===----------------------------------------------------------------------===// 78 | +// Instructions 79 | +//===----------------------------------------------------------------------===// 80 | + 81 | +let Predicates = [HasStdExtM] in { 82 | +def MUL : ALU_rr<0b0000001, 0b000, "mul">; 83 | +def MULH : ALU_rr<0b0000001, 0b001, "mulh">; 84 | +def MULHSU : ALU_rr<0b0000001, 0b010, "mulhsu">; 85 | +def MULHU : ALU_rr<0b0000001, 0b011, "mulhu">; 86 | +def DIV : ALU_rr<0b0000001, 0b100, "div">; 87 | +def DIVU : ALU_rr<0b0000001, 0b101, "divu">; 88 | +def REM : ALU_rr<0b0000001, 0b110, "rem">; 89 | +def REMU : ALU_rr<0b0000001, 0b111, "remu">; 90 | +} // Predicates = [HasStdExtM] 91 | diff --git a/lib/Target/RISCV/RISCVSubtarget.h b/lib/Target/RISCV/RISCVSubtarget.h 92 | index cf8956414aa..77510540009 100644 93 | --- a/lib/Target/RISCV/RISCVSubtarget.h 94 | +++ b/lib/Target/RISCV/RISCVSubtarget.h 95 | @@ -30,6 +30,7 @@ class StringRef; 96 | 97 | class RISCVSubtarget : public RISCVGenSubtargetInfo { 98 | virtual void anchor(); 99 | + bool HasStdExtM; 100 | bool HasRV64 = false; 101 | unsigned XLen = 32; 102 | MVT XLenVT = MVT::i32; 103 | @@ -66,6 +67,7 @@ public: 104 | const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { 105 | return &TSInfo; 106 | } 107 | + bool hasStdExtM() const { return HasStdExtM; } 108 | bool is64Bit() const { return HasRV64; } 109 | MVT getXLenVT() const { return XLenVT; } 110 | unsigned getXLen() const { return XLen; } 111 | diff --git a/test/MC/RISCV/rv32i-invalid.s b/test/MC/RISCV/rv32i-invalid.s 112 | index 3e4ac85ed60..763d4c547a2 100644 113 | --- a/test/MC/RISCV/rv32i-invalid.s 114 | +++ b/test/MC/RISCV/rv32i-invalid.s 115 | @@ -128,3 +128,6 @@ lw a4, a5, 111 # CHECK: :[[@LINE]]:8: error: immediate must be an integer in the 116 | # Too few operands 117 | ori a0, a1 # CHECK: :[[@LINE]]:1: error: too few operands for instruction 118 | xor s2, s2 # CHECK: :[[@LINE]]:1: error: too few operands for instruction 119 | + 120 | +# Instruction not in the base ISA 121 | +mul a4, ra, s0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled 122 | diff --git a/test/MC/RISCV/rv32m-valid.s b/test/MC/RISCV/rv32m-valid.s 123 | new file mode 100644 124 | index 00000000000..70c1c29d3ad 125 | --- /dev/null 126 | +++ b/test/MC/RISCV/rv32m-valid.s 127 | @@ -0,0 +1,33 @@ 128 | +# RUN: llvm-mc %s -triple=riscv32 -mattr=+m -show-encoding \ 129 | +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 130 | +# RUN: llvm-mc %s -triple=riscv64 -mattr=+m -show-encoding \ 131 | +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 132 | +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+m < %s \ 133 | +# RUN: | llvm-objdump -mattr=+m -d - | FileCheck -check-prefix=CHECK-INST %s 134 | +# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+m < %s \ 135 | +# RUN: | llvm-objdump -mattr=+m -d - | FileCheck -check-prefix=CHECK-INST %s 136 | + 137 | +# CHECK-INST: mul a4, ra, s0 138 | +# CHECK: encoding: [0x33,0x87,0x80,0x02] 139 | +mul a4, ra, s0 140 | +# CHECK-INST: mulh ra, zero, zero 141 | +# CHECK: encoding: [0xb3,0x10,0x00,0x02] 142 | +mulh x1, x0, x0 143 | +# CHECK-INST: mulhsu t0, t2, t1 144 | +# CHECK: encoding: [0xb3,0xa2,0x63,0x02] 145 | +mulhsu t0, t2, t1 146 | +# CHECK-INST: mulhu a5, a4, a3 147 | +# CHECK: encoding: [0xb3,0x37,0xd7,0x02] 148 | +mulhu a5, a4, a3 149 | +# CHECK-INST: div s0, s0, s0 150 | +# CHECK: encoding: [0x33,0x44,0x84,0x02] 151 | +div s0, s0, s0 152 | +# CHECK-INST: divu gp, a0, a1 153 | +# CHECK: encoding: [0xb3,0x51,0xb5,0x02] 154 | +divu gp, a0, a1 155 | +# CHECK-INST: rem s2, s2, s8 156 | +# CHECK: encoding: [0x33,0x69,0x89,0x03] 157 | +rem s2, s2, s8 158 | +# CHECK-INST: remu s2, s2, s8 159 | +# CHECK: encoding: [0x33,0x79,0x89,0x03] 160 | +remu x18, x18, x24 161 | -- 162 | 2.16.2 163 | 164 | -------------------------------------------------------------------------------- /0029-RISCV-Add-support-for-llvm.-frameaddress-returnaddre.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Add support for llvm.{frameaddress,returnaddress} intrinsics 4 | 5 | --- 6 | lib/Target/RISCV/RISCVISelLowering.cpp | 57 +++++++++++++++++ 7 | lib/Target/RISCV/RISCVISelLowering.h | 2 + 8 | test/CodeGen/RISCV/frameaddr-returnaddr.ll | 99 ++++++++++++++++++++++++++++++ 9 | 3 files changed, 158 insertions(+) 10 | create mode 100644 test/CodeGen/RISCV/frameaddr-returnaddr.ll 11 | 12 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 13 | index 0dec008a3e9..d5d23129ff9 100644 14 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 16 | @@ -166,6 +166,10 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, 17 | return lowerSELECT(Op, DAG); 18 | case ISD::VASTART: 19 | return lowerVASTART(Op, DAG); 20 | + case ISD::FRAMEADDR: 21 | + return LowerFRAMEADDR(Op, DAG); 22 | + case ISD::RETURNADDR: 23 | + return LowerRETURNADDR(Op, DAG); 24 | } 25 | } 26 | 27 | @@ -284,6 +288,59 @@ SDValue RISCVTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { 28 | MachinePointerInfo(SV)); 29 | } 30 | 31 | +SDValue RISCVTargetLowering::LowerFRAMEADDR(SDValue Op, 32 | + SelectionDAG &DAG) const { 33 | + const RISCVRegisterInfo &RI = *Subtarget.getRegisterInfo(); 34 | + MachineFunction &MF = DAG.getMachineFunction(); 35 | + MachineFrameInfo &MFI = MF.getFrameInfo(); 36 | + MFI.setFrameAddressIsTaken(true); 37 | + unsigned FrameReg = RI.getFrameRegister(MF); 38 | + int XLenInBytes = Subtarget.getXLen() / 8; 39 | + 40 | + EVT VT = Op.getValueType(); 41 | + SDLoc DL(Op); 42 | + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); 43 | + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); 44 | + while (Depth--) { 45 | + int Offset = -(XLenInBytes * 2); 46 | + SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, 47 | + DAG.getIntPtrConstant(Offset, DL)); 48 | + FrameAddr = 49 | + DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); 50 | + } 51 | + return FrameAddr; 52 | +} 53 | + 54 | +SDValue RISCVTargetLowering::LowerRETURNADDR(SDValue Op, 55 | + SelectionDAG &DAG) const { 56 | + const RISCVRegisterInfo &RI = *Subtarget.getRegisterInfo(); 57 | + MachineFunction &MF = DAG.getMachineFunction(); 58 | + MachineFrameInfo &MFI = MF.getFrameInfo(); 59 | + MFI.setReturnAddressIsTaken(true); 60 | + MVT XLenVT = Subtarget.getXLenVT(); 61 | + int XLenInBytes = Subtarget.getXLen() / 8; 62 | + 63 | + if (verifyReturnAddressArgumentIsConstant(Op, DAG)) 64 | + return SDValue(); 65 | + 66 | + EVT VT = Op.getValueType(); 67 | + SDLoc DL(Op); 68 | + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); 69 | + if (Depth) { 70 | + int Off = -XLenInBytes; 71 | + SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); 72 | + SDValue Offset = DAG.getConstant(Off, DL, VT); 73 | + return DAG.getLoad(VT, DL, DAG.getEntryNode(), 74 | + DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset), 75 | + MachinePointerInfo()); 76 | + } 77 | + 78 | + // Return the value of the return address register, marking it an implicit 79 | + // live-in. 80 | + unsigned Reg = MF.addLiveIn(RI.getRARegister(), getRegClassFor(XLenVT)); 81 | + return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, XLenVT); 82 | +} 83 | + 84 | MachineBasicBlock * 85 | RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, 86 | MachineBasicBlock *BB) const { 87 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 88 | index 2f9c202fb64..8ee00cd69a1 100644 89 | --- a/lib/Target/RISCV/RISCVISelLowering.h 90 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 91 | @@ -83,6 +83,8 @@ private: 92 | SDValue lowerExternalSymbol(SDValue Op, SelectionDAG &DAG) const; 93 | SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const; 94 | SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; 95 | + SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; 96 | + SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; 97 | }; 98 | } 99 | 100 | diff --git a/test/CodeGen/RISCV/frameaddr-returnaddr.ll b/test/CodeGen/RISCV/frameaddr-returnaddr.ll 101 | new file mode 100644 102 | index 00000000000..f3dbb8a9662 103 | --- /dev/null 104 | +++ b/test/CodeGen/RISCV/frameaddr-returnaddr.ll 105 | @@ -0,0 +1,99 @@ 106 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 107 | +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ 108 | +; RUN: | FileCheck -check-prefix=RV32I %s 109 | + 110 | +declare void @notdead(i8*) 111 | +declare i8* @llvm.frameaddress(i32) 112 | +declare i8* @llvm.returnaddress(i32) 113 | + 114 | +define i8* @test_frameaddress_0() nounwind { 115 | +; RV32I-LABEL: test_frameaddress_0: 116 | +; RV32I: # %bb.0: 117 | +; RV32I-NEXT: addi sp, sp, -16 118 | +; RV32I-NEXT: sw ra, 12(sp) 119 | +; RV32I-NEXT: sw s0, 8(sp) 120 | +; RV32I-NEXT: addi s0, sp, 16 121 | +; RV32I-NEXT: addi a0, s0, 0 122 | +; RV32I-NEXT: lw s0, 8(sp) 123 | +; RV32I-NEXT: lw ra, 12(sp) 124 | +; RV32I-NEXT: addi sp, sp, 16 125 | +; RV32I-NEXT: jalr zero, ra, 0 126 | + %1 = call i8* @llvm.frameaddress(i32 0) 127 | + ret i8* %1 128 | +} 129 | + 130 | +define i8* @test_frameaddress_2() nounwind { 131 | +; RV32I-LABEL: test_frameaddress_2: 132 | +; RV32I: # %bb.0: 133 | +; RV32I-NEXT: addi sp, sp, -16 134 | +; RV32I-NEXT: sw ra, 12(sp) 135 | +; RV32I-NEXT: sw s0, 8(sp) 136 | +; RV32I-NEXT: addi s0, sp, 16 137 | +; RV32I-NEXT: lw a0, -8(s0) 138 | +; RV32I-NEXT: lw a0, -8(a0) 139 | +; RV32I-NEXT: lw s0, 8(sp) 140 | +; RV32I-NEXT: lw ra, 12(sp) 141 | +; RV32I-NEXT: addi sp, sp, 16 142 | +; RV32I-NEXT: jalr zero, ra, 0 143 | + %1 = call i8* @llvm.frameaddress(i32 2) 144 | + ret i8* %1 145 | +} 146 | + 147 | +define i8* @test_frameaddress_3_alloca() nounwind { 148 | +; RV32I-LABEL: test_frameaddress_3_alloca: 149 | +; RV32I: # %bb.0: 150 | +; RV32I-NEXT: addi sp, sp, -112 151 | +; RV32I-NEXT: sw ra, 108(sp) 152 | +; RV32I-NEXT: sw s0, 104(sp) 153 | +; RV32I-NEXT: addi s0, sp, 112 154 | +; RV32I-NEXT: lui a0, %hi(notdead) 155 | +; RV32I-NEXT: addi a1, a0, %lo(notdead) 156 | +; RV32I-NEXT: addi a0, s0, -108 157 | +; RV32I-NEXT: jalr ra, a1, 0 158 | +; RV32I-NEXT: lw a0, -8(s0) 159 | +; RV32I-NEXT: lw a0, -8(a0) 160 | +; RV32I-NEXT: lw a0, -8(a0) 161 | +; RV32I-NEXT: lw s0, 104(sp) 162 | +; RV32I-NEXT: lw ra, 108(sp) 163 | +; RV32I-NEXT: addi sp, sp, 112 164 | +; RV32I-NEXT: jalr zero, ra, 0 165 | + %1 = alloca [100 x i8] 166 | + %2 = bitcast [100 x i8]* %1 to i8* 167 | + call void @notdead(i8* %2) 168 | + %3 = call i8* @llvm.frameaddress(i32 3) 169 | + ret i8* %3 170 | +} 171 | + 172 | +define i8* @test_returnaddress_0() nounwind { 173 | +; RV32I-LABEL: test_returnaddress_0: 174 | +; RV32I: # %bb.0: 175 | +; RV32I-NEXT: addi sp, sp, -16 176 | +; RV32I-NEXT: sw ra, 12(sp) 177 | +; RV32I-NEXT: sw s0, 8(sp) 178 | +; RV32I-NEXT: addi s0, sp, 16 179 | +; RV32I-NEXT: addi a0, ra, 0 180 | +; RV32I-NEXT: lw s0, 8(sp) 181 | +; RV32I-NEXT: lw ra, 12(sp) 182 | +; RV32I-NEXT: addi sp, sp, 16 183 | +; RV32I-NEXT: jalr zero, ra, 0 184 | + %1 = call i8* @llvm.returnaddress(i32 0) 185 | + ret i8* %1 186 | +} 187 | + 188 | +define i8* @test_returnaddress_2() nounwind { 189 | +; RV32I-LABEL: test_returnaddress_2: 190 | +; RV32I: # %bb.0: 191 | +; RV32I-NEXT: addi sp, sp, -16 192 | +; RV32I-NEXT: sw ra, 12(sp) 193 | +; RV32I-NEXT: sw s0, 8(sp) 194 | +; RV32I-NEXT: addi s0, sp, 16 195 | +; RV32I-NEXT: lw a0, -8(s0) 196 | +; RV32I-NEXT: lw a0, -8(a0) 197 | +; RV32I-NEXT: lw a0, -4(a0) 198 | +; RV32I-NEXT: lw s0, 8(sp) 199 | +; RV32I-NEXT: lw ra, 12(sp) 200 | +; RV32I-NEXT: addi sp, sp, 16 201 | +; RV32I-NEXT: jalr zero, ra, 0 202 | + %1 = call i8* @llvm.returnaddress(i32 2) 203 | + ret i8* %1 204 | +} 205 | -- 206 | 2.16.2 207 | 208 | -------------------------------------------------------------------------------- /0054-RISCV-Add-minimum-necessary-for-RV32D-codegen-for-fa.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Add minimum necessary for RV32D codegen for fadd.d and 4 | load/store from stack locations 5 | 6 | --- 7 | lib/Target/RISCV/RISCVISelLowering.cpp | 32 +++++++++++++++++ 8 | lib/Target/RISCV/RISCVISelLowering.h | 6 ++++ 9 | lib/Target/RISCV/RISCVInstrInfoD.td | 15 ++++++++ 10 | test/CodeGen/RISCV/double-arith.ll | 23 +++++++++++++ 11 | test/CodeGen/RISCV/double-mem.ll | 63 ++++++++++++++++++++++++++++++++++ 12 | 5 files changed, 139 insertions(+) 13 | create mode 100644 test/CodeGen/RISCV/double-arith.ll 14 | create mode 100644 test/CodeGen/RISCV/double-mem.ll 15 | 16 | diff --git a/lib/Target/RISCV/RISCVISelLowering.cpp b/lib/Target/RISCV/RISCVISelLowering.cpp 17 | index 572dafaf66d..44a2538a665 100644 18 | --- a/lib/Target/RISCV/RISCVISelLowering.cpp 19 | +++ b/lib/Target/RISCV/RISCVISelLowering.cpp 20 | @@ -47,6 +47,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, 21 | 22 | if (Subtarget.hasStdExtF()) 23 | addRegisterClass(MVT::f32, &RISCV::FPR32RegClass); 24 | + if (Subtarget.hasStdExtD()) 25 | + addRegisterClass(MVT::f64, &RISCV::FPR64RegClass); 26 | 27 | // Compute derived properties from the register classes. 28 | computeRegisterProperties(STI.getRegisterInfo()); 29 | @@ -1153,3 +1155,33 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, 30 | 31 | return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 32 | } 33 | + 34 | +MVT RISCVTargetLowering::getRegisterTypeForCallingConv(MVT VT) const { 35 | + // If passing f64 for the soft-float ABI on an RV32IFD target, ensure that 36 | + // the value is split into i32 parts despite f64 being legal. 37 | + // TODO: adjust when hard-float ABI is implemented. 38 | + if (!Subtarget.is64Bit() && VT == MVT::f64) 39 | + return MVT::i32; 40 | + return getRegisterType(VT); 41 | +} 42 | + 43 | +MVT RISCVTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context, 44 | + EVT VT) const { 45 | + // If passing f64 for the soft-float ABI on an RV32IFD target, ensure that 46 | + // the value is split into i32 parts despite f64 being legal. 47 | + // TODO: adjust when hard-float ABI is implemented. 48 | + if (!Subtarget.is64Bit() && VT.getSimpleVT() == MVT::f64) 49 | + return MVT::i32; 50 | + return getRegisterType(Context, VT); 51 | +} 52 | + 53 | +unsigned 54 | +RISCVTargetLowering::getNumRegistersForCallingConv(LLVMContext &Context, 55 | + EVT VT) const { 56 | + // If passing f64 for the soft-float ABI on an RV32IFD target, ensure that 57 | + // the value is split into i32 parts despite f64 being legal. 58 | + // TODO: adjust when hard-float ABI is implemented. 59 | + if (!Subtarget.is64Bit() && VT.getSimpleVT() == MVT::f64) 60 | + return 2; 61 | + return getNumRegisters(Context, VT); 62 | +} 63 | diff --git a/lib/Target/RISCV/RISCVISelLowering.h b/lib/Target/RISCV/RISCVISelLowering.h 64 | index a54b5c1532f..3e49c2db7f3 100644 65 | --- a/lib/Target/RISCV/RISCVISelLowering.h 66 | +++ b/lib/Target/RISCV/RISCVISelLowering.h 67 | @@ -51,6 +51,12 @@ public: 68 | EmitInstrWithCustomInserter(MachineInstr &MI, 69 | MachineBasicBlock *BB) const override; 70 | 71 | + MVT getRegisterTypeForCallingConv(MVT VT) const override; 72 | + MVT getRegisterTypeForCallingConv(LLVMContext &Context, 73 | + EVT VT) const override; 74 | + unsigned getNumRegistersForCallingConv(LLVMContext &Context, 75 | + EVT VT) const override; 76 | + 77 | private: 78 | void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, 79 | const SmallVectorImpl &Ins, 80 | diff --git a/lib/Target/RISCV/RISCVInstrInfoD.td b/lib/Target/RISCV/RISCVInstrInfoD.td 81 | index 8a78e372e8b..1d29a7c086b 100644 82 | --- a/lib/Target/RISCV/RISCVInstrInfoD.td 83 | +++ b/lib/Target/RISCV/RISCVInstrInfoD.td 84 | @@ -159,3 +159,18 @@ def FMV_D_X : FPUnaryOp_r<0b1111001, 0b000, FPR64, GPR, "fmv.d.x"> { 85 | let rs2 = 0b00000; 86 | } 87 | } // Predicates = [HasStdExtD, IsRV64] 88 | + 89 | +//===----------------------------------------------------------------------===// 90 | +// Pseudo-instructions and codegen patterns 91 | +//===----------------------------------------------------------------------===// 92 | + 93 | +class PatFpr64Fpr64DynFrm 94 | + : Pat<(OpNode FPR64:$rs1, FPR64:$rs2), (Inst $rs1, $rs2, 0b111)>; 95 | + 96 | +let Predicates = [HasStdExtD] in { 97 | + 98 | +/// Float arithmetic operations 99 | + 100 | +def : PatFpr64Fpr64DynFrm; 101 | + 102 | +} // Predicates = [HasStdExtD] 103 | diff --git a/test/CodeGen/RISCV/double-arith.ll b/test/CodeGen/RISCV/double-arith.ll 104 | new file mode 100644 105 | index 00000000000..f759b4d3b97 106 | --- /dev/null 107 | +++ b/test/CodeGen/RISCV/double-arith.ll 108 | @@ -0,0 +1,23 @@ 109 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 110 | +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ 111 | +; RUN: | FileCheck -check-prefix=RV32IFD %s 112 | + 113 | +define double @fadd_d(double %a, double %b) nounwind { 114 | +; RV32IFD-LABEL: fadd_d: 115 | +; RV32IFD: # %bb.0: 116 | +; RV32IFD-NEXT: addi sp, sp, -32 117 | +; RV32IFD-NEXT: sw a3, 20(sp) 118 | +; RV32IFD-NEXT: sw a2, 16(sp) 119 | +; RV32IFD-NEXT: sw a1, 28(sp) 120 | +; RV32IFD-NEXT: sw a0, 24(sp) 121 | +; RV32IFD-NEXT: fld ft0, 16(sp) 122 | +; RV32IFD-NEXT: fld ft1, 24(sp) 123 | +; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 124 | +; RV32IFD-NEXT: fsd ft0, 8(sp) 125 | +; RV32IFD-NEXT: lw a0, 8(sp) 126 | +; RV32IFD-NEXT: lw a1, 12(sp) 127 | +; RV32IFD-NEXT: addi sp, sp, 32 128 | +; RV32IFD-NEXT: jalr zero, ra, 0 129 | + %1 = fadd double %a, %b 130 | + ret double %1 131 | +} 132 | diff --git a/test/CodeGen/RISCV/double-mem.ll b/test/CodeGen/RISCV/double-mem.ll 133 | new file mode 100644 134 | index 00000000000..16a4383f616 135 | --- /dev/null 136 | +++ b/test/CodeGen/RISCV/double-mem.ll 137 | @@ -0,0 +1,63 @@ 138 | +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 139 | +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ 140 | +; RUN: | FileCheck -check-prefix=RV32IFD %s 141 | + 142 | +declare void @notdead(i8*) 143 | + 144 | +define double @fld_stack(double %a) nounwind { 145 | +; Tests RISCV::LdFPR64_FI 146 | +; RV32IFD-LABEL: fld_stack: 147 | +; RV32IFD: # %bb.0: 148 | +; RV32IFD-NEXT: addi sp, sp, -32 149 | +; RV32IFD-NEXT: sw ra, 28(sp) 150 | +; RV32IFD-NEXT: sw a1, 12(sp) 151 | +; RV32IFD-NEXT: sw a0, 8(sp) 152 | +; RV32IFD-NEXT: lui a0, %hi(notdead) 153 | +; RV32IFD-NEXT: addi a1, a0, %lo(notdead) 154 | +; RV32IFD-NEXT: addi a0, sp, 16 155 | +; RV32IFD-NEXT: jalr ra, a1, 0 156 | +; RV32IFD-NEXT: fld ft0, 8(sp) 157 | +; RV32IFD-NEXT: fld ft1, 16(sp) 158 | +; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 159 | +; RV32IFD-NEXT: fsd ft0, 0(sp) 160 | +; RV32IFD-NEXT: lw a0, 0(sp) 161 | +; RV32IFD-NEXT: lw a1, 4(sp) 162 | +; RV32IFD-NEXT: lw ra, 28(sp) 163 | +; RV32IFD-NEXT: addi sp, sp, 32 164 | +; RV32IFD-NEXT: jalr zero, ra, 0 165 | + %1 = alloca double, align 8 166 | + %2 = bitcast double* %1 to i8* 167 | + call void @notdead(i8* %2) 168 | + %3 = load double, double* %1 169 | + %4 = fadd double %3, %a ; force load in to FPR64 170 | + ret double %4 171 | +} 172 | + 173 | +define void @fsd_stack(double %a, double %b) nounwind { 174 | +; Tests RISCV::StFPR64_FI 175 | +; RV32IFD-LABEL: fsd_stack: 176 | +; RV32IFD: # %bb.0: 177 | +; RV32IFD-NEXT: addi sp, sp, -32 178 | +; RV32IFD-NEXT: sw ra, 28(sp) 179 | +; RV32IFD-NEXT: sw a3, 4(sp) 180 | +; RV32IFD-NEXT: sw a2, 0(sp) 181 | +; RV32IFD-NEXT: sw a1, 12(sp) 182 | +; RV32IFD-NEXT: sw a0, 8(sp) 183 | +; RV32IFD-NEXT: fld ft0, 0(sp) 184 | +; RV32IFD-NEXT: fld ft1, 8(sp) 185 | +; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 186 | +; RV32IFD-NEXT: fsd ft0, 16(sp) 187 | +; RV32IFD-NEXT: lui a0, %hi(notdead) 188 | +; RV32IFD-NEXT: addi a1, a0, %lo(notdead) 189 | +; RV32IFD-NEXT: addi a0, sp, 16 190 | +; RV32IFD-NEXT: jalr ra, a1, 0 191 | +; RV32IFD-NEXT: lw ra, 28(sp) 192 | +; RV32IFD-NEXT: addi sp, sp, 32 193 | +; RV32IFD-NEXT: jalr zero, ra, 0 194 | + %1 = fadd double %a, %b ; force store from FPR64 195 | + %2 = alloca double, align 8 196 | + store double %1, double* %2 197 | + %3 = bitcast double* %2 to i8* 198 | + call void @notdead(i8* %3) 199 | + ret void 200 | +} 201 | -- 202 | 2.16.2 203 | 204 | -------------------------------------------------------------------------------- /0083-RISCV-Add-ELFObjectFileBase-getRISCVFeatures-let-llv.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Add ELFObjectFileBase::getRISCVFeatures let llvm-objdump 4 | could get RISCV target feature 5 | 6 | llvm-objdump could get C feature by ELF::EF_RISCV_RVC e_flag, 7 | so then we don't have to add -mattr=+c on the command line. 8 | 9 | Differential Revision: https://reviews.llvm.org/D42629 10 | Patch by Shiva Chen. 11 | --- 12 | include/llvm/Object/ELFObjectFile.h | 2 ++ 13 | lib/Object/ELFObjectFile.cpp | 13 +++++++++++++ 14 | test/MC/RISCV/cnop.s | 2 +- 15 | test/MC/RISCV/fixups-compressed.s | 2 +- 16 | test/MC/RISCV/rv32c-only-valid.s | 2 +- 17 | test/MC/RISCV/rv32c-valid.s | 4 ++-- 18 | test/MC/RISCV/rv32dc-valid.s | 2 +- 19 | test/MC/RISCV/rv32fc-valid.s | 2 +- 20 | test/MC/RISCV/rv64c-valid.s | 2 +- 21 | test/MC/RISCV/rv64dc-valid.s | 8 ++++---- 22 | 10 files changed, 27 insertions(+), 12 deletions(-) 23 | 24 | diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h 25 | index 9c691e1c283..4d001039238 100644 26 | --- a/include/llvm/Object/ELFObjectFile.h 27 | +++ b/include/llvm/Object/ELFObjectFile.h 28 | @@ -80,6 +80,8 @@ public: 29 | 30 | SubtargetFeatures getARMFeatures() const; 31 | 32 | + SubtargetFeatures getRISCVFeatures() const; 33 | + 34 | void setARMSubArch(Triple &TheTriple) const override; 35 | }; 36 | 37 | diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp 38 | index 3c1bdf5a1de..e806c8f28b1 100644 39 | --- a/lib/Object/ELFObjectFile.cpp 40 | +++ b/lib/Object/ELFObjectFile.cpp 41 | @@ -238,12 +238,25 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { 42 | return Features; 43 | } 44 | 45 | +SubtargetFeatures ELFObjectFileBase::getRISCVFeatures() const { 46 | + SubtargetFeatures Features; 47 | + unsigned PlatformFlags = getPlatformFlags(); 48 | + 49 | + if (PlatformFlags & ELF::EF_RISCV_RVC) { 50 | + Features.AddFeature("c"); 51 | + } 52 | + 53 | + return Features; 54 | +} 55 | + 56 | SubtargetFeatures ELFObjectFileBase::getFeatures() const { 57 | switch (getEMachine()) { 58 | case ELF::EM_MIPS: 59 | return getMIPSFeatures(); 60 | case ELF::EM_ARM: 61 | return getARMFeatures(); 62 | + case ELF::EM_RISCV: 63 | + return getRISCVFeatures(); 64 | default: 65 | return SubtargetFeatures(); 66 | } 67 | diff --git a/test/MC/RISCV/cnop.s b/test/MC/RISCV/cnop.s 68 | index 8d526263724..ff2acee8868 100644 69 | --- a/test/MC/RISCV/cnop.s 70 | +++ b/test/MC/RISCV/cnop.s 71 | @@ -1,5 +1,5 @@ 72 | # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \ 73 | -# RUN: | llvm-objdump -mattr=+c -d - | FileCheck -check-prefix=CHECK-INST %s 74 | +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s 75 | 76 | # alpha and main are 8 byte alignment 77 | # but the alpha function's size is 6 78 | diff --git a/test/MC/RISCV/fixups-compressed.s b/test/MC/RISCV/fixups-compressed.s 79 | index bf6cbfc3556..65e4c773eca 100644 80 | --- a/test/MC/RISCV/fixups-compressed.s 81 | +++ b/test/MC/RISCV/fixups-compressed.s 82 | @@ -1,7 +1,7 @@ 83 | # RUN: llvm-mc %s -triple riscv32 -mattr=+c -show-encoding \ 84 | # RUN: | FileCheck -check-prefix=CHECK-FIXUP %s 85 | # RUN: llvm-mc -triple riscv32 -filetype=obj -mattr=+c < %s \ 86 | -# RUN: | llvm-objdump -mattr=+c -d - | FileCheck -check-prefix=CHECK-INSTR %s 87 | +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s 88 | 89 | .LBB0_2: 90 | # CHECK-FIXUP: fixup A - offset: 0, value: .LBB0_2, kind: fixup_riscv_rvc_jump 91 | diff --git a/test/MC/RISCV/rv32c-only-valid.s b/test/MC/RISCV/rv32c-only-valid.s 92 | index f46c2a3ea93..1cc8494fe47 100644 93 | --- a/test/MC/RISCV/rv32c-only-valid.s 94 | +++ b/test/MC/RISCV/rv32c-only-valid.s 95 | @@ -1,7 +1,7 @@ 96 | # RUN: llvm-mc -triple=riscv32 -mattr=+c -riscv-no-aliases -show-encoding < %s \ 97 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 98 | # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c -riscv-no-aliases < %s \ 99 | -# RUN: | llvm-objdump -mattr=+c -d - | FileCheck -check-prefix=CHECK-INST %s 100 | +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s 101 | # RUN: not llvm-mc -triple riscv32 \ 102 | # RUN: -show-encoding < %s 2>&1 \ 103 | # RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s 104 | diff --git a/test/MC/RISCV/rv32c-valid.s b/test/MC/RISCV/rv32c-valid.s 105 | index 338c8e0ee75..449e3be51a7 100644 106 | --- a/test/MC/RISCV/rv32c-valid.s 107 | +++ b/test/MC/RISCV/rv32c-valid.s 108 | @@ -3,10 +3,10 @@ 109 | # RUN: llvm-mc -triple=riscv64 -mattr=+c -riscv-no-aliases -show-encoding < %s \ 110 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 111 | # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \ 112 | -# RUN: | llvm-objdump -mattr=+c -riscv-no-aliases -d - \ 113 | +# RUN: | llvm-objdump -riscv-no-aliases -d - \ 114 | # RUN: | FileCheck -check-prefix=CHECK-INST %s 115 | # RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c < %s \ 116 | -# RUN: | llvm-objdump -mattr=+c -riscv-no-aliases -d - \ 117 | +# RUN: | llvm-objdump -riscv-no-aliases -d - \ 118 | # RUN: | FileCheck -check-prefix=CHECK-INST %s 119 | 120 | # TODO: more exhaustive testing of immediate encoding. 121 | diff --git a/test/MC/RISCV/rv32dc-valid.s b/test/MC/RISCV/rv32dc-valid.s 122 | index 507b39170ec..764bcbd2fb1 100644 123 | --- a/test/MC/RISCV/rv32dc-valid.s 124 | +++ b/test/MC/RISCV/rv32dc-valid.s 125 | @@ -1,7 +1,7 @@ 126 | # RUN: llvm-mc %s -triple=riscv32 -mattr=+c,+d -riscv-no-aliases -show-encoding \ 127 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 128 | # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c,+d < %s \ 129 | -# RUN: | llvm-objdump -mattr=+c,+d -riscv-no-aliases -d - \ 130 | +# RUN: | llvm-objdump -mattr=+d -riscv-no-aliases -d - \ 131 | # RUN: | FileCheck -check-prefix=CHECK-INST %s 132 | # RUN: not llvm-mc -triple riscv32 -mattr=+c\ 133 | # RUN: -riscv-no-aliases -show-encoding < %s 2>&1 \ 134 | diff --git a/test/MC/RISCV/rv32fc-valid.s b/test/MC/RISCV/rv32fc-valid.s 135 | index a66498c1468..f744759cd07 100644 136 | --- a/test/MC/RISCV/rv32fc-valid.s 137 | +++ b/test/MC/RISCV/rv32fc-valid.s 138 | @@ -1,7 +1,7 @@ 139 | # RUN: llvm-mc %s -triple=riscv32 -mattr=+c,+f -riscv-no-aliases -show-encoding \ 140 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 141 | # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c,+f < %s \ 142 | -# RUN: | llvm-objdump -mattr=+c,+f -riscv-no-aliases -d - \ 143 | +# RUN: | llvm-objdump -mattr=+f -riscv-no-aliases -d - \ 144 | # RUN: | FileCheck -check-prefix=CHECK-INST %s 145 | # RUN: not llvm-mc -triple riscv32 -mattr=+c \ 146 | # RUN: -riscv-no-aliases -show-encoding < %s 2>&1 \ 147 | diff --git a/test/MC/RISCV/rv64c-valid.s b/test/MC/RISCV/rv64c-valid.s 148 | index 5e7b901ad0e..c436fe5414c 100644 149 | --- a/test/MC/RISCV/rv64c-valid.s 150 | +++ b/test/MC/RISCV/rv64c-valid.s 151 | @@ -1,7 +1,7 @@ 152 | # RUN: llvm-mc -triple=riscv64 -mattr=+c -riscv-no-aliases -show-encoding < %s \ 153 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 154 | # RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c < %s \ 155 | -# RUN: | llvm-objdump -mattr=+c -riscv-no-aliases -d - \ 156 | +# RUN: | llvm-objdump -riscv-no-aliases -d - \ 157 | # RUN: | FileCheck -check-prefix=CHECK-INST %s 158 | # RUN: not llvm-mc -triple riscv64 \ 159 | # RUN: -riscv-no-aliases -show-encoding < %s 2>&1 \ 160 | diff --git a/test/MC/RISCV/rv64dc-valid.s b/test/MC/RISCV/rv64dc-valid.s 161 | index 0d7ea62e9b0..e54f6411ad3 100644 162 | --- a/test/MC/RISCV/rv64dc-valid.s 163 | +++ b/test/MC/RISCV/rv64dc-valid.s 164 | @@ -1,13 +1,13 @@ 165 | -# RUN: llvm-mc %s -triple=riscv64 -mattr=+c,+d -show-encoding \ 166 | +# RUN: llvm-mc %s -triple=riscv64 -mattr=+c,+d -riscv-no-aliases -show-encoding \ 167 | # RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s 168 | # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+d < %s \ 169 | -# RUN: | llvm-objdump -mattr=+c,+d -d - \ 170 | +# RUN: | llvm-objdump -mattr=+d -riscv-no-aliases -d - \ 171 | # RUN: | FileCheck -check-prefix=CHECK-INST %s 172 | # RUN: not llvm-mc -triple riscv64 -mattr=+c\ 173 | -# RUN: -show-encoding < %s 2>&1 \ 174 | +# RUN: -riscv-no-aliases -show-encoding < %s 2>&1 \ 175 | # RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s 176 | # RUN: not llvm-mc -triple riscv64 \ 177 | -# RUN: -show-encoding < %s 2>&1 \ 178 | +# RUN: -riscv-no-aliases -show-encoding < %s 2>&1 \ 179 | # RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s 180 | 181 | # CHECK-INST: c.fldsp fs0, 504(sp) 182 | -- 183 | 2.16.2 184 | 185 | -------------------------------------------------------------------------------- /0002-RISCV-Recognise-riscv32-and-riscv64-in-triple-parsin.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Recognise riscv32 and riscv64 in triple parsing code 4 | 5 | Differential Revision: https://reviews.llvm.org/D23557 6 | Upstream commit: https://reviews.llvm.org/rL285708 7 | --- 8 | include/llvm/ADT/Triple.h | 2 ++ 9 | lib/Support/Triple.cpp | 21 +++++++++++++++++++++ 10 | unittests/ADT/TripleTest.cpp | 36 ++++++++++++++++++++++++++++++++++++ 11 | 3 files changed, 59 insertions(+) 12 | 13 | diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h 14 | index 965bd246b83..00fa9c08299 100644 15 | --- a/include/llvm/ADT/Triple.h 16 | +++ b/include/llvm/ADT/Triple.h 17 | @@ -66,6 +66,8 @@ public: 18 | ppc64le, // PPC64LE: powerpc64le 19 | r600, // R600: AMD GPUs HD2XXX - HD6XXX 20 | amdgcn, // AMDGCN: AMD GCN GPUs 21 | + riscv32, // RISC-V (32-bit): riscv32 22 | + riscv64, // RISC-V (64-bit): riscv64 23 | sparc, // Sparc: sparc 24 | sparcv9, // Sparcv9: Sparcv9 25 | sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant 26 | diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp 27 | index 9b1a739c911..5062fc43266 100644 28 | --- a/lib/Support/Triple.cpp 29 | +++ b/lib/Support/Triple.cpp 30 | @@ -41,6 +41,8 @@ StringRef Triple::getArchTypeName(ArchType Kind) { 31 | case ppc: return "powerpc"; 32 | case r600: return "r600"; 33 | case amdgcn: return "amdgcn"; 34 | + case riscv32: return "riscv32"; 35 | + case riscv64: return "riscv64"; 36 | case sparc: return "sparc"; 37 | case sparcv9: return "sparcv9"; 38 | case sparcel: return "sparcel"; 39 | @@ -141,6 +143,9 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { 40 | case shave: return "shave"; 41 | case wasm32: 42 | case wasm64: return "wasm"; 43 | + 44 | + case riscv32: 45 | + case riscv64: return "riscv"; 46 | } 47 | } 48 | 49 | @@ -273,6 +278,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { 50 | .Case("ppc64le", ppc64le) 51 | .Case("r600", r600) 52 | .Case("amdgcn", amdgcn) 53 | + .Case("riscv32", riscv32) 54 | + .Case("riscv64", riscv64) 55 | .Case("hexagon", hexagon) 56 | .Case("sparc", sparc) 57 | .Case("sparcel", sparcel) 58 | @@ -398,6 +405,8 @@ static Triple::ArchType parseArch(StringRef ArchName) { 59 | .Case("nios2", Triple::nios2) 60 | .Case("r600", Triple::r600) 61 | .Case("amdgcn", Triple::amdgcn) 62 | + .Case("riscv32", Triple::riscv32) 63 | + .Case("riscv64", Triple::riscv64) 64 | .Case("hexagon", Triple::hexagon) 65 | .Cases("s390x", "systemz", Triple::systemz) 66 | .Case("sparc", Triple::sparc) 67 | @@ -647,6 +656,8 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { 68 | case Triple::r600: 69 | case Triple::renderscript32: 70 | case Triple::renderscript64: 71 | + case Triple::riscv32: 72 | + case Triple::riscv64: 73 | case Triple::shave: 74 | case Triple::sparc: 75 | case Triple::sparcel: 76 | @@ -1185,6 +1196,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { 77 | case llvm::Triple::nvptx: 78 | case llvm::Triple::ppc: 79 | case llvm::Triple::r600: 80 | + case llvm::Triple::riscv32: 81 | case llvm::Triple::sparc: 82 | case llvm::Triple::sparcel: 83 | case llvm::Triple::tce: 84 | @@ -1214,6 +1226,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { 85 | case llvm::Triple::nvptx64: 86 | case llvm::Triple::ppc64: 87 | case llvm::Triple::ppc64le: 88 | + case llvm::Triple::riscv64: 89 | case llvm::Triple::sparcv9: 90 | case llvm::Triple::systemz: 91 | case llvm::Triple::x86_64: 92 | @@ -1268,6 +1281,7 @@ Triple Triple::get32BitArchVariant() const { 93 | case Triple::nvptx: 94 | case Triple::ppc: 95 | case Triple::r600: 96 | + case Triple::riscv32: 97 | case Triple::sparc: 98 | case Triple::sparcel: 99 | case Triple::tce: 100 | @@ -1291,6 +1305,7 @@ Triple Triple::get32BitArchVariant() const { 101 | case Triple::nvptx64: T.setArch(Triple::nvptx); break; 102 | case Triple::ppc64: T.setArch(Triple::ppc); break; 103 | case Triple::sparcv9: T.setArch(Triple::sparc); break; 104 | + case Triple::riscv64: T.setArch(Triple::riscv32); break; 105 | case Triple::x86_64: T.setArch(Triple::x86); break; 106 | case Triple::amdil64: T.setArch(Triple::amdil); break; 107 | case Triple::hsail64: T.setArch(Triple::hsail); break; 108 | @@ -1335,6 +1350,7 @@ Triple Triple::get64BitArchVariant() const { 109 | case Triple::nvptx64: 110 | case Triple::ppc64: 111 | case Triple::ppc64le: 112 | + case Triple::riscv64: 113 | case Triple::sparcv9: 114 | case Triple::systemz: 115 | case Triple::x86_64: 116 | @@ -1351,6 +1367,7 @@ Triple Triple::get64BitArchVariant() const { 117 | case Triple::nvptx: T.setArch(Triple::nvptx64); break; 118 | case Triple::ppc: T.setArch(Triple::ppc64); break; 119 | case Triple::sparc: T.setArch(Triple::sparcv9); break; 120 | + case Triple::riscv32: T.setArch(Triple::riscv64); break; 121 | case Triple::x86: T.setArch(Triple::x86_64); break; 122 | case Triple::amdil: T.setArch(Triple::amdil64); break; 123 | case Triple::hsail: T.setArch(Triple::hsail64); break; 124 | @@ -1385,6 +1402,8 @@ Triple Triple::getBigEndianArchVariant() const { 125 | case Triple::nvptx64: 126 | case Triple::nvptx: 127 | case Triple::r600: 128 | + case Triple::riscv32: 129 | + case Triple::riscv64: 130 | case Triple::shave: 131 | case Triple::spir64: 132 | case Triple::spir: 133 | @@ -1471,6 +1490,8 @@ bool Triple::isLittleEndian() const { 134 | case Triple::nvptx: 135 | case Triple::ppc64le: 136 | case Triple::r600: 137 | + case Triple::riscv32: 138 | + case Triple::riscv64: 139 | case Triple::shave: 140 | case Triple::sparcel: 141 | case Triple::spir64: 142 | diff --git a/unittests/ADT/TripleTest.cpp b/unittests/ADT/TripleTest.cpp 143 | index 93606a98076..c19ad43c723 100644 144 | --- a/unittests/ADT/TripleTest.cpp 145 | +++ b/unittests/ADT/TripleTest.cpp 146 | @@ -295,6 +295,24 @@ TEST(TripleTest, ParsedIDs) { 147 | EXPECT_EQ(Triple::AMDPAL, T.getOS()); 148 | EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); 149 | 150 | + T = Triple("riscv32-unknown-unknown"); 151 | + EXPECT_EQ(Triple::riscv32, T.getArch()); 152 | + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); 153 | + EXPECT_EQ(Triple::UnknownOS, T.getOS()); 154 | + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); 155 | + 156 | + T = Triple("riscv64-unknown-linux"); 157 | + EXPECT_EQ(Triple::riscv64, T.getArch()); 158 | + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); 159 | + EXPECT_EQ(Triple::Linux, T.getOS()); 160 | + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); 161 | + 162 | + T = Triple("riscv64-unknown-freebsd"); 163 | + EXPECT_EQ(Triple::riscv64, T.getArch()); 164 | + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); 165 | + EXPECT_EQ(Triple::FreeBSD, T.getOS()); 166 | + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); 167 | + 168 | T = Triple("armv7hl-suse-linux-gnueabi"); 169 | EXPECT_EQ(Triple::arm, T.getArch()); 170 | EXPECT_EQ(Triple::SUSE, T.getVendor()); 171 | @@ -639,6 +657,16 @@ TEST(TripleTest, BitWidthPredicates) { 172 | EXPECT_FALSE(T.isArch16Bit()); 173 | EXPECT_TRUE(T.isArch32Bit()); 174 | EXPECT_FALSE(T.isArch64Bit()); 175 | + 176 | + T.setArch(Triple::riscv32); 177 | + EXPECT_FALSE(T.isArch16Bit()); 178 | + EXPECT_TRUE(T.isArch32Bit()); 179 | + EXPECT_FALSE(T.isArch64Bit()); 180 | + 181 | + T.setArch(Triple::riscv64); 182 | + EXPECT_FALSE(T.isArch16Bit()); 183 | + EXPECT_FALSE(T.isArch32Bit()); 184 | + EXPECT_TRUE(T.isArch64Bit()); 185 | } 186 | 187 | TEST(TripleTest, BitWidthArchVariants) { 188 | @@ -730,6 +758,14 @@ TEST(TripleTest, BitWidthArchVariants) { 189 | EXPECT_EQ(Triple::wasm32, T.get32BitArchVariant().getArch()); 190 | EXPECT_EQ(Triple::wasm64, T.get64BitArchVariant().getArch()); 191 | 192 | + T.setArch(Triple::riscv32); 193 | + EXPECT_EQ(Triple::riscv32, T.get32BitArchVariant().getArch()); 194 | + EXPECT_EQ(Triple::riscv64, T.get64BitArchVariant().getArch()); 195 | + 196 | + T.setArch(Triple::riscv64); 197 | + EXPECT_EQ(Triple::riscv32, T.get32BitArchVariant().getArch()); 198 | + EXPECT_EQ(Triple::riscv64, T.get64BitArchVariant().getArch()); 199 | + 200 | T.setArch(Triple::thumbeb); 201 | EXPECT_EQ(Triple::thumbeb, T.get32BitArchVariant().getArch()); 202 | EXPECT_EQ(Triple::aarch64_be, T.get64BitArchVariant().getArch()); 203 | -- 204 | 2.16.2 205 | 206 | -------------------------------------------------------------------------------- /docs/03-assembly-parsing.mkd: -------------------------------------------------------------------------------- 1 | # Implementing support for parsing RISC-V assembly 2 | 3 | ## Overview 4 | 5 | Warning: Unfortunately there's quite a lot of code that needs to be written 6 | before the assembler becomes testable. 7 | 8 | The necessary steps are: 9 | * Add a minimal set of TableGen files describing the RISC-V registers, 10 | instruction formats, and instructions 11 | * Add a RISC-V MCTargetDesc in order to correctly initialise the MC layer 12 | (machine code layer) 13 | * Add a RISCVAsmParser that is capable of parsing simple RISC-V assembly files 14 | * Add a RISCVInstPrinter in order to make the whole thing testable (this will 15 | be done in the next part of this series) 16 | 17 | When targeting an architecture that already has a working assembler, you could 18 | avoid implementing MC-layer support altogether and just rely on an external 19 | assembler. However, starting with the MC layer is actually a useful way of 20 | incrementally building up the backend. 21 | 22 | ## Adding TableGen files 23 | 24 | [TableGen](http://llvm.org/docs/TableGen/) is a domain-specific language which 25 | provides a concise and readable syntax for specifying records. For an LLVM 26 | backend, these records include registers, instruction formats, and instruction 27 | definitions. The [RISC-V specifications](https://riscv.org/specifications/) 28 | are a useful reference for this. 29 | 30 | ### Adding RISCVRegisterInfo.td 31 | 32 | RISCVRegisterInfo.td should define each register with a name such as `x1` as 33 | well as the ABI name, `ra`. Each register definition is subclassed from 34 | `Register`, defined in `include/llvm/Target/Target.td`. In order to support an 35 | alternate name, you must define a unique `RegAltNameIndex`: 36 | 37 | def ABIRegAltName : RegAltNameIndex 38 | 39 | Then, for each Register, specify a list of alternate names as well as the 40 | valid RegAltNameIndices. For instance in the following, `"zero"` is the 41 | `ABIRegAltName`: 42 | 43 | let RegAltNameIndices = [ABIRegAltName] in { 44 | def X0_32 : RISCVReg32<0, "x0", ["zero"]>, DwarfRegNum<[0]>; 45 | 46 | Registers are collected into an appropriate `RegisterClass`. The order of 47 | registers in a class reflects the preferred register allocation sequence. 48 | However, given that the focus is just on the MC layer, for now you can add 49 | them in ascending order: 50 | 51 | def GPR : RegisterClass<"RISCV", [i32], 32, (add 52 | (sequence "X%u_32", 0, 31) 53 | )>; 54 | 55 | ### Adding RISCVInstrFormats.td 56 | 57 | Each instruction format definition serves as a superclass for individual 58 | RISC-V instructions. The instruction format specifies how instructions of that 59 | type should be encoded. For instance, the 'I' format instruction has a 3-bit 60 | funct field, a 7-bit opcode field, two registers, and a 12-bit immediate 61 | field. 62 | 63 | class FI funct3, bits<7> opcode, dag outs, dag ins, string asmstr, 64 | list pattern> 65 | : RISCVInst 66 | { 67 | bits<12> imm12; 68 | bits<5> rs1; 69 | bits<5> rd; 70 | 71 | let Inst{31-20} = imm12; 72 | let Inst{19-15} = rs1; 73 | let Inst{14-12} = funct3; 74 | let Inst{11-7} = rd; 75 | let Opcode = opcode; 76 | } 77 | 78 | 79 | ### Adding RISCVInstrInfo.td 80 | 81 | With the formats defined, adding the instructions is relatively 82 | straightforward. For instance: 83 | 84 | def simm12 : Operand; 85 | 86 | class ALU_ri funct3, string OpcodeStr> : 87 | FI {} 89 | 90 | def ADDI : ALU_ri<0b000, "addi">; 91 | 92 | Defining the `ALU_ri` class helps to avoid repetition when specifying the 93 | group of similarly defined reg-imm ALU instructions. 94 | 95 | The string `"\t$rd, $rs1, $imm12"` specifies how the instruction's operands 96 | are represented in textual assembly. 97 | 98 | ### Adding RISCV.td and checking the descriptions 99 | 100 | RISCV.td is the top-level TableGen file. As well as incorporating the register 101 | and instruction definitions via includes, it contains definitions of processor 102 | models and features, as well as other miscellaneous backend settings. 103 | 104 | You can check the produced TableGen records by executing: 105 | 106 | ./bin/llvm-tblgen -I ../lib/Target/RISCV/ -I ../include/ -I ../lib/Target/ ../lib/Target/RISCV/RISCV.td 107 | 108 | You can then add tablegen invocations to `lib/Target/RISCV/CMakeLists.txt` 109 | that generate backend C++ code based on the .td contents: 110 | 111 | set(LLVM_TARGET_DEFINITIONS RISCV.td) 112 | 113 | tablegen(LLVM RISCVGenRegisterInfo.inc -gen-register-info) 114 | tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info) 115 | 116 | add_public_tablegen_target(RISCVCommonTableGen) 117 | 118 | ## Adding a RISC-V MCTargetDesc 119 | 120 | The next step is to add a minimal set of classes under the RISCVMCTargetDesc 121 | sub-directory. This will provide just enough functionality to emit a RISC-V 122 | ELF. 123 | 124 | I found it easier to start top-down rather than bottom-up, so start with 125 | `RISCVMCTargetDesc.cpp`. This is primarily responsible for registering the 126 | necessary MC-layer classes. 127 | 128 | extern "C" void LLVMInitializeRISCVTargetMC() { 129 | for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) { 130 | TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo); 131 | TargetRegistry::RegisterMCInstrInfo(*T, createRISCVMCInstrInfo); 132 | TargetRegistry::RegisterMCRegInfo(*T, createRISCVMCRegisterInfo); 133 | TargetRegistry::RegisterMCAsmBackend(*T, createRISCVAsmBackend); 134 | TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter); 135 | } 136 | } 137 | 138 | To understand this registration process, it's worth looking at how the LLVM 139 | `TargetRegistry` works. A typical LLVM front-end or tool (e.g. llvm-mc) will 140 | get an instance of `Target`, and then call methods such as `createMCRegInfo` 141 | in order to obtain an instance of the given type. 142 | `LLVMInitializeRISCVTargetMC` is responsible for registering these instances, 143 | ready for later retrieval. The easiest way of finding the minimal set of MC 144 | classes to implement is to work through them one-by-one and see what fails 145 | when executing `./bin/llvm-mc -arch=riscv64 -filetype=obj foo.s`. 146 | 147 | * RISCVMCAsmInfo 148 | * Inherits from MCAsmInfoELF. Just needs to specify a few key details such 149 | as the comment string. 150 | * The 'anchor' method is provided as per the [LLVM coding 151 | standards](http://llvm.org/docs/CodingStandards.html#provide-a-virtual-method-anchor-for-classes-in-headers). 152 | As explained in [this StackOverflow 153 | answer](https://stackoverflow.com/questions/16801222/out-of-line-virtual-method), 154 | creating a dummy virtual method like this ensures that the vtable is emitted 155 | in only one .o file. 156 | * RISCVMCInstrInfo 157 | * Trivial, just need to call `InitRISCVMCInstrInfo`, which is generated by 158 | tablegen. 159 | * RISCVAsmBackend 160 | * All methods are stubbed out, with the exception of 161 | `RISCVAsmBackend::writeNopData`. The canonical NOP for RISC-V is `addi x0, 162 | x0, 0` (0x13). 163 | * RISCVELFObjectWriter 164 | * Derives from `MCELFObjectTargetWriter`, methods are all stubbed out. 165 | * RISCVMCCodeEmitter 166 | * Converts RISC-V instructions (MCInst) to encoded instructions. Most of the 167 | work is done by `getBinaryCodeForInstr`, which is generated by TableGen. 168 | 169 | Finally, add `MCTargetDesc` to `lib/Target/RISCV/CMakeLists.txt` and create 170 | `lib/Target/RISCV/MCTargetDesc/CMakeLists.txt`. 171 | 172 | At this point, you can try `./bin/llvm-mc -arch=riscv64 -filetype=obj foo.s`, 173 | which should result in "error: this target does not support assembly parsing". 174 | Progress! 175 | 176 | ## Implementing RISCVAsmParser 177 | 178 | Next up is the implementation of 179 | `lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp`. A number of functions are 180 | auto-generated from RISCVInstrInfo.td, such as `MatchRegisterName`, 181 | `MatchRegisterAltName`, and `MatchInstructionImpl`. 182 | 183 | There are three major components to RISCVAsmParser: 184 | * `RISCVOperand`, representing an instruction operand (a token, register, or 185 | immediate). 186 | * The top-level `MatchAndEmitInstruction`. This primarily calls 187 | `MatchEmitInstructionImpl`. However, you will need to write code that handles 188 | the various failure conditions, emitting an appropriate diagnostic. 189 | * Methods to parse instructions and operands. 190 | 191 | There is the potential for confusion with some of these method 192 | implementations. Some will return a bool, others a MatchResult. A return value 193 | of false typically indicates success. 194 | 195 | At this point, it should be possible to assemble a simple file using 196 | `llvm-mc`. The `-stats` and `-as-lex` options are useful to track what is 197 | going on. 198 | -------------------------------------------------------------------------------- /0066-RISCV-Implement-RISCVRegisterInfo-enableMultipleCopy.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Implement RISCVRegisterInfo::enableMultipleCopyHints() 4 | 5 | https://reviews.llvm.org/D38128 and r319754 introduced an opt-in register 6 | allocator tweak with the stated intention of enabling it by default once 7 | backends have all opted in. It doesn't seem to hurt us at least, so let's opt 8 | in. 9 | --- 10 | lib/Target/RISCV/RISCVRegisterInfo.h | 2 + 11 | test/CodeGen/RISCV/double-select-fcmp.ll | 2 +- 12 | test/CodeGen/RISCV/vararg.ll | 100 +++++++++++++++---------------- 13 | 3 files changed, 53 insertions(+), 51 deletions(-) 14 | 15 | diff --git a/lib/Target/RISCV/RISCVRegisterInfo.h b/lib/Target/RISCV/RISCVRegisterInfo.h 16 | index a81dea09401..6ae0cfd8c0f 100644 17 | --- a/lib/Target/RISCV/RISCVRegisterInfo.h 18 | +++ b/lib/Target/RISCV/RISCVRegisterInfo.h 19 | @@ -51,6 +51,8 @@ struct RISCVRegisterInfo : public RISCVGenRegisterInfo { 20 | bool trackLivenessAfterRegAlloc(const MachineFunction &) const override { 21 | return true; 22 | } 23 | + 24 | + bool enableMultipleCopyHints() const override { return true; } 25 | }; 26 | } 27 | 28 | diff --git a/test/CodeGen/RISCV/double-select-fcmp.ll b/test/CodeGen/RISCV/double-select-fcmp.ll 29 | index abb9ee5c8be..3a5ec81b44e 100644 30 | --- a/test/CodeGen/RISCV/double-select-fcmp.ll 31 | +++ b/test/CodeGen/RISCV/double-select-fcmp.ll 32 | @@ -5,8 +5,8 @@ 33 | define double @select_fcmp_false(double %a, double %b) nounwind { 34 | ; RV32IFD-LABEL: select_fcmp_false: 35 | ; RV32IFD: # %bb.0: 36 | -; RV32IFD-NEXT: addi a0, a2, 0 37 | ; RV32IFD-NEXT: addi a1, a3, 0 38 | +; RV32IFD-NEXT: addi a0, a2, 0 39 | ; RV32IFD-NEXT: jalr zero, ra, 0 40 | %1 = fcmp false double %a, %b 41 | %2 = select i1 %1, double %a, double %b 42 | diff --git a/test/CodeGen/RISCV/vararg.ll b/test/CodeGen/RISCV/vararg.ll 43 | index 2564d91361e..e9b7b07ff0c 100644 44 | --- a/test/CodeGen/RISCV/vararg.ll 45 | +++ b/test/CodeGen/RISCV/vararg.ll 46 | @@ -383,24 +383,24 @@ define double @va3(i32 %a, double %b, ...) nounwind { 47 | ; RV32I-FPELIM: # %bb.0: 48 | ; RV32I-FPELIM-NEXT: addi sp, sp, -32 49 | ; RV32I-FPELIM-NEXT: sw ra, 4(sp) 50 | +; RV32I-FPELIM-NEXT: addi t0, a2, 0 51 | +; RV32I-FPELIM-NEXT: addi a0, a1, 0 52 | ; RV32I-FPELIM-NEXT: sw a7, 28(sp) 53 | ; RV32I-FPELIM-NEXT: sw a6, 24(sp) 54 | ; RV32I-FPELIM-NEXT: sw a5, 20(sp) 55 | ; RV32I-FPELIM-NEXT: sw a4, 16(sp) 56 | ; RV32I-FPELIM-NEXT: sw a3, 12(sp) 57 | -; RV32I-FPELIM-NEXT: addi a0, sp, 27 58 | -; RV32I-FPELIM-NEXT: sw a0, 0(sp) 59 | -; RV32I-FPELIM-NEXT: lui a0, %hi(__adddf3) 60 | -; RV32I-FPELIM-NEXT: addi a5, a0, %lo(__adddf3) 61 | -; RV32I-FPELIM-NEXT: addi a0, sp, 19 62 | -; RV32I-FPELIM-NEXT: andi a0, a0, -8 63 | -; RV32I-FPELIM-NEXT: lw a4, 0(a0) 64 | -; RV32I-FPELIM-NEXT: ori a0, a0, 4 65 | -; RV32I-FPELIM-NEXT: lw a3, 0(a0) 66 | -; RV32I-FPELIM-NEXT: addi a0, a1, 0 67 | -; RV32I-FPELIM-NEXT: addi a1, a2, 0 68 | -; RV32I-FPELIM-NEXT: addi a2, a4, 0 69 | -; RV32I-FPELIM-NEXT: jalr ra, a5, 0 70 | +; RV32I-FPELIM-NEXT: addi a1, sp, 27 71 | +; RV32I-FPELIM-NEXT: sw a1, 0(sp) 72 | +; RV32I-FPELIM-NEXT: lui a1, %hi(__adddf3) 73 | +; RV32I-FPELIM-NEXT: addi a4, a1, %lo(__adddf3) 74 | +; RV32I-FPELIM-NEXT: addi a1, sp, 19 75 | +; RV32I-FPELIM-NEXT: andi a1, a1, -8 76 | +; RV32I-FPELIM-NEXT: lw a2, 0(a1) 77 | +; RV32I-FPELIM-NEXT: ori a1, a1, 4 78 | +; RV32I-FPELIM-NEXT: lw a3, 0(a1) 79 | +; RV32I-FPELIM-NEXT: addi a1, t0, 0 80 | +; RV32I-FPELIM-NEXT: jalr ra, a4, 0 81 | ; RV32I-FPELIM-NEXT: lw ra, 4(sp) 82 | ; RV32I-FPELIM-NEXT: addi sp, sp, 32 83 | ; RV32I-FPELIM-NEXT: jalr zero, ra, 0 84 | @@ -411,24 +411,24 @@ define double @va3(i32 %a, double %b, ...) nounwind { 85 | ; RV32I-WITHFP-NEXT: sw ra, 20(sp) 86 | ; RV32I-WITHFP-NEXT: sw s0, 16(sp) 87 | ; RV32I-WITHFP-NEXT: addi s0, sp, 24 88 | +; RV32I-WITHFP-NEXT: addi t0, a2, 0 89 | +; RV32I-WITHFP-NEXT: addi a0, a1, 0 90 | ; RV32I-WITHFP-NEXT: sw a7, 20(s0) 91 | ; RV32I-WITHFP-NEXT: sw a6, 16(s0) 92 | ; RV32I-WITHFP-NEXT: sw a5, 12(s0) 93 | ; RV32I-WITHFP-NEXT: sw a4, 8(s0) 94 | ; RV32I-WITHFP-NEXT: sw a3, 4(s0) 95 | -; RV32I-WITHFP-NEXT: addi a0, s0, 19 96 | -; RV32I-WITHFP-NEXT: sw a0, -12(s0) 97 | -; RV32I-WITHFP-NEXT: lui a0, %hi(__adddf3) 98 | -; RV32I-WITHFP-NEXT: addi a5, a0, %lo(__adddf3) 99 | -; RV32I-WITHFP-NEXT: addi a0, s0, 11 100 | -; RV32I-WITHFP-NEXT: andi a0, a0, -8 101 | -; RV32I-WITHFP-NEXT: lw a4, 0(a0) 102 | -; RV32I-WITHFP-NEXT: ori a0, a0, 4 103 | -; RV32I-WITHFP-NEXT: lw a3, 0(a0) 104 | -; RV32I-WITHFP-NEXT: addi a0, a1, 0 105 | -; RV32I-WITHFP-NEXT: addi a1, a2, 0 106 | -; RV32I-WITHFP-NEXT: addi a2, a4, 0 107 | -; RV32I-WITHFP-NEXT: jalr ra, a5, 0 108 | +; RV32I-WITHFP-NEXT: addi a1, s0, 19 109 | +; RV32I-WITHFP-NEXT: sw a1, -12(s0) 110 | +; RV32I-WITHFP-NEXT: lui a1, %hi(__adddf3) 111 | +; RV32I-WITHFP-NEXT: addi a4, a1, %lo(__adddf3) 112 | +; RV32I-WITHFP-NEXT: addi a1, s0, 11 113 | +; RV32I-WITHFP-NEXT: andi a1, a1, -8 114 | +; RV32I-WITHFP-NEXT: lw a2, 0(a1) 115 | +; RV32I-WITHFP-NEXT: ori a1, a1, 4 116 | +; RV32I-WITHFP-NEXT: lw a3, 0(a1) 117 | +; RV32I-WITHFP-NEXT: addi a1, t0, 0 118 | +; RV32I-WITHFP-NEXT: jalr ra, a4, 0 119 | ; RV32I-WITHFP-NEXT: lw s0, 16(sp) 120 | ; RV32I-WITHFP-NEXT: lw ra, 20(sp) 121 | ; RV32I-WITHFP-NEXT: addi sp, sp, 48 122 | @@ -455,25 +455,25 @@ define double @va3_va_arg(i32 %a, double %b, ...) nounwind { 123 | ; RV32I-FPELIM: # %bb.0: 124 | ; RV32I-FPELIM-NEXT: addi sp, sp, -32 125 | ; RV32I-FPELIM-NEXT: sw ra, 4(sp) 126 | +; RV32I-FPELIM-NEXT: addi t0, a2, 0 127 | +; RV32I-FPELIM-NEXT: addi a0, a1, 0 128 | ; RV32I-FPELIM-NEXT: sw a7, 28(sp) 129 | ; RV32I-FPELIM-NEXT: sw a6, 24(sp) 130 | ; RV32I-FPELIM-NEXT: sw a5, 20(sp) 131 | ; RV32I-FPELIM-NEXT: sw a4, 16(sp) 132 | ; RV32I-FPELIM-NEXT: sw a3, 12(sp) 133 | -; RV32I-FPELIM-NEXT: addi a0, sp, 19 134 | -; RV32I-FPELIM-NEXT: andi a0, a0, -8 135 | -; RV32I-FPELIM-NEXT: ori a3, a0, 4 136 | +; RV32I-FPELIM-NEXT: addi a1, sp, 19 137 | +; RV32I-FPELIM-NEXT: andi a1, a1, -8 138 | +; RV32I-FPELIM-NEXT: ori a3, a1, 4 139 | ; RV32I-FPELIM-NEXT: sw a3, 0(sp) 140 | -; RV32I-FPELIM-NEXT: lw a4, 0(a0) 141 | -; RV32I-FPELIM-NEXT: addi a0, a3, 4 142 | -; RV32I-FPELIM-NEXT: sw a0, 0(sp) 143 | -; RV32I-FPELIM-NEXT: lui a0, %hi(__adddf3) 144 | -; RV32I-FPELIM-NEXT: addi a5, a0, %lo(__adddf3) 145 | +; RV32I-FPELIM-NEXT: lw a2, 0(a1) 146 | +; RV32I-FPELIM-NEXT: addi a1, a3, 4 147 | +; RV32I-FPELIM-NEXT: sw a1, 0(sp) 148 | +; RV32I-FPELIM-NEXT: lui a1, %hi(__adddf3) 149 | +; RV32I-FPELIM-NEXT: addi a4, a1, %lo(__adddf3) 150 | ; RV32I-FPELIM-NEXT: lw a3, 0(a3) 151 | -; RV32I-FPELIM-NEXT: addi a0, a1, 0 152 | -; RV32I-FPELIM-NEXT: addi a1, a2, 0 153 | -; RV32I-FPELIM-NEXT: addi a2, a4, 0 154 | -; RV32I-FPELIM-NEXT: jalr ra, a5, 0 155 | +; RV32I-FPELIM-NEXT: addi a1, t0, 0 156 | +; RV32I-FPELIM-NEXT: jalr ra, a4, 0 157 | ; RV32I-FPELIM-NEXT: lw ra, 4(sp) 158 | ; RV32I-FPELIM-NEXT: addi sp, sp, 32 159 | ; RV32I-FPELIM-NEXT: jalr zero, ra, 0 160 | @@ -484,25 +484,25 @@ define double @va3_va_arg(i32 %a, double %b, ...) nounwind { 161 | ; RV32I-WITHFP-NEXT: sw ra, 20(sp) 162 | ; RV32I-WITHFP-NEXT: sw s0, 16(sp) 163 | ; RV32I-WITHFP-NEXT: addi s0, sp, 24 164 | +; RV32I-WITHFP-NEXT: addi t0, a2, 0 165 | +; RV32I-WITHFP-NEXT: addi a0, a1, 0 166 | ; RV32I-WITHFP-NEXT: sw a7, 20(s0) 167 | ; RV32I-WITHFP-NEXT: sw a6, 16(s0) 168 | ; RV32I-WITHFP-NEXT: sw a5, 12(s0) 169 | ; RV32I-WITHFP-NEXT: sw a4, 8(s0) 170 | ; RV32I-WITHFP-NEXT: sw a3, 4(s0) 171 | -; RV32I-WITHFP-NEXT: addi a0, s0, 11 172 | -; RV32I-WITHFP-NEXT: andi a0, a0, -8 173 | -; RV32I-WITHFP-NEXT: ori a3, a0, 4 174 | +; RV32I-WITHFP-NEXT: addi a1, s0, 11 175 | +; RV32I-WITHFP-NEXT: andi a1, a1, -8 176 | +; RV32I-WITHFP-NEXT: ori a3, a1, 4 177 | ; RV32I-WITHFP-NEXT: sw a3, -12(s0) 178 | -; RV32I-WITHFP-NEXT: lw a4, 0(a0) 179 | -; RV32I-WITHFP-NEXT: addi a0, a3, 4 180 | -; RV32I-WITHFP-NEXT: sw a0, -12(s0) 181 | -; RV32I-WITHFP-NEXT: lui a0, %hi(__adddf3) 182 | -; RV32I-WITHFP-NEXT: addi a5, a0, %lo(__adddf3) 183 | +; RV32I-WITHFP-NEXT: lw a2, 0(a1) 184 | +; RV32I-WITHFP-NEXT: addi a1, a3, 4 185 | +; RV32I-WITHFP-NEXT: sw a1, -12(s0) 186 | +; RV32I-WITHFP-NEXT: lui a1, %hi(__adddf3) 187 | +; RV32I-WITHFP-NEXT: addi a4, a1, %lo(__adddf3) 188 | ; RV32I-WITHFP-NEXT: lw a3, 0(a3) 189 | -; RV32I-WITHFP-NEXT: addi a0, a1, 0 190 | -; RV32I-WITHFP-NEXT: addi a1, a2, 0 191 | -; RV32I-WITHFP-NEXT: addi a2, a4, 0 192 | -; RV32I-WITHFP-NEXT: jalr ra, a5, 0 193 | +; RV32I-WITHFP-NEXT: addi a1, t0, 0 194 | +; RV32I-WITHFP-NEXT: jalr ra, a4, 0 195 | ; RV32I-WITHFP-NEXT: lw s0, 16(sp) 196 | ; RV32I-WITHFP-NEXT: lw ra, 20(sp) 197 | ; RV32I-WITHFP-NEXT: addi sp, sp, 48 198 | -- 199 | 2.16.2 200 | 201 | -------------------------------------------------------------------------------- /0021-RISCV-Use-register-X0-ZERO-for-constant-0.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Use register X0 (ZERO) for constant 0 4 | 5 | The obvious approach of defining a pattern like the one below actually doesn't 6 | work: 7 | `def : Pat<(i32 0), (i32 X0)>;` 8 | 9 | As was noted when Lanai made this change (https://reviews.llvm.org/rL288215), 10 | attempting to handle the constant 0 in tablegen leads to assertions due to a 11 | physical register being used where a virtual register is expected. 12 | --- 13 | lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 25 +++++++++++++++++++++++++ 14 | test/CodeGen/RISCV/bare-select.ll | 3 +-- 15 | test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll | 20 ++++++++------------ 16 | test/CodeGen/RISCV/sext-zext-trunc.ll | 19 ++++--------------- 17 | 4 files changed, 38 insertions(+), 29 deletions(-) 18 | 19 | diff --git a/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp 20 | index 6ce7a163f2f..daac114b557 100644 21 | --- a/lib/Target/RISCV/RISCVISelDAGToDAG.cpp 22 | +++ b/lib/Target/RISCV/RISCVISelDAGToDAG.cpp 23 | @@ -26,6 +26,8 @@ using namespace llvm; 24 | // SelectionDAG operations. 25 | namespace { 26 | class RISCVDAGToDAGISel final : public SelectionDAGISel { 27 | + const RISCVSubtarget *Subtarget; 28 | + 29 | public: 30 | explicit RISCVDAGToDAGISel(RISCVTargetMachine &TargetMachine) 31 | : SelectionDAGISel(TargetMachine) {} 32 | @@ -34,6 +36,11 @@ public: 33 | return "RISCV DAG->DAG Pattern Instruction Selection"; 34 | } 35 | 36 | + bool runOnMachineFunction(MachineFunction &MF) override { 37 | + Subtarget = &MF.getSubtarget(); 38 | + return SelectionDAGISel::runOnMachineFunction(MF); 39 | + } 40 | + 41 | void Select(SDNode *Node) override; 42 | 43 | // Include the pieces autogenerated from the target description. 44 | @@ -42,6 +49,9 @@ public: 45 | } 46 | 47 | void RISCVDAGToDAGISel::Select(SDNode *Node) { 48 | + unsigned Opcode = Node->getOpcode(); 49 | + MVT XLenVT = Subtarget->getXLenVT(); 50 | + 51 | // If we have a custom node, we have already selected 52 | if (Node->isMachineOpcode()) { 53 | DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 54 | @@ -49,6 +59,21 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) { 55 | return; 56 | } 57 | 58 | + // Instruction Selection not handled by the auto-generated tablegen selection 59 | + // should be handled here. 60 | + EVT VT = Node->getValueType(0); 61 | + if (Opcode == ISD::Constant && VT == XLenVT) { 62 | + auto *ConstNode = cast(Node); 63 | + // Materialize zero constants as copies from X0. This allows the coalescer 64 | + // to propagate these into other instructions. 65 | + if (ConstNode->isNullValue()) { 66 | + SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node), 67 | + RISCV::X0, XLenVT); 68 | + ReplaceNode(Node, New.getNode()); 69 | + return; 70 | + } 71 | + } 72 | + 73 | // Select the default instruction. 74 | SelectCode(Node); 75 | } 76 | diff --git a/test/CodeGen/RISCV/bare-select.ll b/test/CodeGen/RISCV/bare-select.ll 77 | index 016e3a7a9cd..a46afe27143 100644 78 | --- a/test/CodeGen/RISCV/bare-select.ll 79 | +++ b/test/CodeGen/RISCV/bare-select.ll 80 | @@ -6,8 +6,7 @@ define i32 @bare_select(i1 %a, i32 %b, i32 %c) { 81 | ; RV32I-LABEL: bare_select: 82 | ; RV32I: # %bb.0: 83 | ; RV32I-NEXT: andi a0, a0, 1 84 | -; RV32I-NEXT: addi a3, zero, 0 85 | -; RV32I-NEXT: bne a0, a3, .LBB0_2 86 | +; RV32I-NEXT: bne a0, zero, .LBB0_2 87 | ; RV32I-NEXT: # %bb.1: 88 | ; RV32I-NEXT: addi a1, a2, 0 89 | ; RV32I-NEXT: .LBB0_2: 90 | diff --git a/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll b/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll 91 | index 6ccb5e00be5..150dfed3573 100644 92 | --- a/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll 93 | +++ b/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll 94 | @@ -86,8 +86,7 @@ define i8 @test_cttz_i8(i8 %a) nounwind { 95 | ; RV32I-NEXT: addi a1, a0, 0 96 | ; RV32I-NEXT: addi a0, zero, 8 97 | ; RV32I-NEXT: andi a2, a1, 255 98 | -; RV32I-NEXT: addi a3, zero, 0 99 | -; RV32I-NEXT: beq a2, a3, .LBB3_2 100 | +; RV32I-NEXT: beq a2, zero, .LBB3_2 101 | ; RV32I-NEXT: jal zero, .LBB3_1 102 | ; RV32I-NEXT: .LBB3_1: # %cond.false 103 | ; RV32I-NEXT: addi a0, a1, -1 104 | @@ -131,8 +130,7 @@ define i16 @test_cttz_i16(i16 %a) nounwind { 105 | ; RV32I-NEXT: lui a2, 16 106 | ; RV32I-NEXT: addi a2, a2, -1 107 | ; RV32I-NEXT: and a2, a1, a2 108 | -; RV32I-NEXT: addi a3, zero, 0 109 | -; RV32I-NEXT: beq a2, a3, .LBB4_2 110 | +; RV32I-NEXT: beq a2, zero, .LBB4_2 111 | ; RV32I-NEXT: jal zero, .LBB4_1 112 | ; RV32I-NEXT: .LBB4_1: # %cond.false 113 | ; RV32I-NEXT: addi a0, a1, -1 114 | @@ -173,8 +171,7 @@ define i32 @test_cttz_i32(i32 %a) nounwind { 115 | ; RV32I-NEXT: sw ra, 12(s0) 116 | ; RV32I-NEXT: addi a1, a0, 0 117 | ; RV32I-NEXT: addi a0, zero, 32 118 | -; RV32I-NEXT: addi a2, zero, 0 119 | -; RV32I-NEXT: beq a1, a2, .LBB5_2 120 | +; RV32I-NEXT: beq a1, zero, .LBB5_2 121 | ; RV32I-NEXT: jal zero, .LBB5_1 122 | ; RV32I-NEXT: .LBB5_1: # %cond.false 123 | ; RV32I-NEXT: addi a0, a1, -1 124 | @@ -215,8 +212,7 @@ define i32 @test_ctlz_i32(i32 %a) nounwind { 125 | ; RV32I-NEXT: sw ra, 12(s0) 126 | ; RV32I-NEXT: addi a1, a0, 0 127 | ; RV32I-NEXT: addi a0, zero, 32 128 | -; RV32I-NEXT: addi a2, zero, 0 129 | -; RV32I-NEXT: beq a1, a2, .LBB6_2 130 | +; RV32I-NEXT: beq a1, zero, .LBB6_2 131 | ; RV32I-NEXT: jal zero, .LBB6_1 132 | ; RV32I-NEXT: .LBB6_1: # %cond.false 133 | ; RV32I-NEXT: srli a0, a1, 1 134 | @@ -314,13 +310,13 @@ define i64 @test_cttz_i64(i64 %a) nounwind { 135 | ; RV32I-NEXT: addi a0, a1, 0 136 | ; RV32I-NEXT: addi a1, s3, 0 137 | ; RV32I-NEXT: jalr ra, s6, 0 138 | -; RV32I-NEXT: addi a1, zero, 0 139 | -; RV32I-NEXT: bne s2, a1, .LBB7_2 140 | +; RV32I-NEXT: bne s2, zero, .LBB7_2 141 | ; RV32I-NEXT: # %bb.1: 142 | ; RV32I-NEXT: srli a0, a0, 24 143 | ; RV32I-NEXT: addi s1, a0, 32 144 | ; RV32I-NEXT: .LBB7_2: 145 | ; RV32I-NEXT: addi a0, s1, 0 146 | +; RV32I-NEXT: addi a1, zero, 0 147 | ; RV32I-NEXT: lw s7, 0(s0) 148 | ; RV32I-NEXT: lw s6, 4(s0) 149 | ; RV32I-NEXT: lw s5, 8(s0) 150 | @@ -494,13 +490,13 @@ define i64 @test_cttz_i64_zero_undef(i64 %a) nounwind { 151 | ; RV32I-NEXT: addi a0, a1, 0 152 | ; RV32I-NEXT: addi a1, s3, 0 153 | ; RV32I-NEXT: jalr ra, s6, 0 154 | -; RV32I-NEXT: addi a1, zero, 0 155 | -; RV32I-NEXT: bne s2, a1, .LBB11_2 156 | +; RV32I-NEXT: bne s2, zero, .LBB11_2 157 | ; RV32I-NEXT: # %bb.1: 158 | ; RV32I-NEXT: srli a0, a0, 24 159 | ; RV32I-NEXT: addi s1, a0, 32 160 | ; RV32I-NEXT: .LBB11_2: 161 | ; RV32I-NEXT: addi a0, s1, 0 162 | +; RV32I-NEXT: addi a1, zero, 0 163 | ; RV32I-NEXT: lw s7, 0(s0) 164 | ; RV32I-NEXT: lw s6, 4(s0) 165 | ; RV32I-NEXT: lw s5, 8(s0) 166 | diff --git a/test/CodeGen/RISCV/sext-zext-trunc.ll b/test/CodeGen/RISCV/sext-zext-trunc.ll 167 | index 2a13685fcd5..80bd2d2b204 100644 168 | --- a/test/CodeGen/RISCV/sext-zext-trunc.ll 169 | +++ b/test/CodeGen/RISCV/sext-zext-trunc.ll 170 | @@ -2,52 +2,41 @@ 171 | ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ 172 | ; RUN: | FileCheck %s -check-prefix=RV32I 173 | 174 | -; FIXME: an unncessary register is allocated just to store 0. X0 should be 175 | -; used instead 176 | - 177 | define i8 @sext_i1_to_i8(i1 %a) { 178 | -; TODO: the addi that stores 0 in t1 is unnecessary 179 | ; RV32I-LABEL: sext_i1_to_i8: 180 | ; RV32I: # %bb.0: 181 | ; RV32I-NEXT: andi a0, a0, 1 182 | -; RV32I-NEXT: addi a1, zero, 0 183 | -; RV32I-NEXT: sub a0, a1, a0 184 | +; RV32I-NEXT: sub a0, zero, a0 185 | ; RV32I-NEXT: jalr zero, ra, 0 186 | %1 = sext i1 %a to i8 187 | ret i8 %1 188 | } 189 | 190 | define i16 @sext_i1_to_i16(i1 %a) { 191 | -; TODO: the addi that stores 0 in t1 is unnecessary 192 | ; RV32I-LABEL: sext_i1_to_i16: 193 | ; RV32I: # %bb.0: 194 | ; RV32I-NEXT: andi a0, a0, 1 195 | -; RV32I-NEXT: addi a1, zero, 0 196 | -; RV32I-NEXT: sub a0, a1, a0 197 | +; RV32I-NEXT: sub a0, zero, a0 198 | ; RV32I-NEXT: jalr zero, ra, 0 199 | %1 = sext i1 %a to i16 200 | ret i16 %1 201 | } 202 | 203 | define i32 @sext_i1_to_i32(i1 %a) { 204 | -; TODO: the addi that stores 0 in t1 is unnecessary 205 | ; RV32I-LABEL: sext_i1_to_i32: 206 | ; RV32I: # %bb.0: 207 | ; RV32I-NEXT: andi a0, a0, 1 208 | -; RV32I-NEXT: addi a1, zero, 0 209 | -; RV32I-NEXT: sub a0, a1, a0 210 | +; RV32I-NEXT: sub a0, zero, a0 211 | ; RV32I-NEXT: jalr zero, ra, 0 212 | %1 = sext i1 %a to i32 213 | ret i32 %1 214 | } 215 | 216 | define i64 @sext_i1_to_i64(i1 %a) { 217 | -; TODO: the addi that stores 0 in t1 is unnecessary 218 | ; RV32I-LABEL: sext_i1_to_i64: 219 | ; RV32I: # %bb.0: 220 | ; RV32I-NEXT: andi a0, a0, 1 221 | -; RV32I-NEXT: addi a1, zero, 0 222 | -; RV32I-NEXT: sub a0, a1, a0 223 | +; RV32I-NEXT: sub a0, zero, a0 224 | ; RV32I-NEXT: addi a1, a0, 0 225 | ; RV32I-NEXT: jalr zero, ra, 0 226 | %1 = sext i1 %a to i64 227 | -- 228 | 2.16.2 229 | 230 | -------------------------------------------------------------------------------- /0080-RISCV-Encode-RISCV-specific-ELF-e_flags-to-RISCV-Bin.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Encode RISCV specific ELF e_flags to RISCV Binary by 4 | RISCVTargetStreamer 5 | 6 | Differential Revision: https://reviews.llvm.org/D41658 7 | Patch by Shiva Chen. 8 | --- 9 | lib/Target/RISCV/MCTargetDesc/CMakeLists.txt | 2 ++ 10 | lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp | 39 ++++++++++++++++++++++ 11 | lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h | 24 +++++++++++++ 12 | .../RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp | 12 +++++++ 13 | .../RISCV/MCTargetDesc/RISCVTargetStreamer.cpp | 18 ++++++++++ 14 | .../RISCV/MCTargetDesc/RISCVTargetStreamer.h | 22 ++++++++++++ 15 | test/MC/RISCV/elf-flags.s | 13 ++++++++ 16 | 7 files changed, 130 insertions(+) 17 | create mode 100644 lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp 18 | create mode 100644 lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h 19 | create mode 100644 lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp 20 | create mode 100644 lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h 21 | create mode 100644 test/MC/RISCV/elf-flags.s 22 | 23 | diff --git a/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt b/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt 24 | index 60429647edd..d9f4188aa75 100644 25 | --- a/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt 26 | +++ b/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt 27 | @@ -5,4 +5,6 @@ add_llvm_library(LLVMRISCVDesc 28 | RISCVMCCodeEmitter.cpp 29 | RISCVMCExpr.cpp 30 | RISCVMCTargetDesc.cpp 31 | + RISCVTargetStreamer.cpp 32 | + RISCVELFStreamer.cpp 33 | ) 34 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp 35 | new file mode 100644 36 | index 00000000000..243f8ed7fb5 37 | --- /dev/null 38 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp 39 | @@ -0,0 +1,39 @@ 40 | +//===-- RISCVELFStreamer.cpp - RISCV ELF Target Streamer Methods ----------===// 41 | +// 42 | +// The LLVM Compiler Infrastructure 43 | +// 44 | +// This file is distributed under the University of Illinois Open Source 45 | +// License. See LICENSE.TXT for details. 46 | +// 47 | +//===----------------------------------------------------------------------===// 48 | +// 49 | +// This file provides RISCV specific target streamer methods. 50 | +// 51 | +//===----------------------------------------------------------------------===// 52 | + 53 | +#include "RISCVELFStreamer.h" 54 | +#include "RISCVMCTargetDesc.h" 55 | +#include "llvm/BinaryFormat/ELF.h" 56 | +#include "llvm/MC/MCSubtargetInfo.h" 57 | + 58 | +using namespace llvm; 59 | + 60 | +// This part is for ELF object output. 61 | +RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S, 62 | + const MCSubtargetInfo &STI) 63 | + : RISCVTargetStreamer(S) { 64 | + MCAssembler &MCA = getStreamer().getAssembler(); 65 | + 66 | + const FeatureBitset &Features = STI.getFeatureBits(); 67 | + 68 | + unsigned EFlags = MCA.getELFHeaderEFlags(); 69 | + 70 | + if (Features[RISCV::FeatureStdExtC]) 71 | + EFlags |= ELF::EF_RISCV_RVC; 72 | + 73 | + MCA.setELFHeaderEFlags(EFlags); 74 | +} 75 | + 76 | +MCELFStreamer &RISCVTargetELFStreamer::getStreamer() { 77 | + return static_cast(Streamer); 78 | +} 79 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h 80 | new file mode 100644 81 | index 00000000000..d3cfbe3e83c 82 | --- /dev/null 83 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h 84 | @@ -0,0 +1,24 @@ 85 | +//===-- RISCVELFStreamer.h - RISCV ELF Target Streamer ---------*- C++ -*--===// 86 | +// 87 | +// The LLVM Compiler Infrastructure 88 | +// 89 | +// This file is distributed under the University of Illinois Open Source 90 | +// License. See LICENSE.TXT for details. 91 | +// 92 | +//===----------------------------------------------------------------------===// 93 | + 94 | +#ifndef LLVM_LIB_TARGET_RISCV_RISCVELFSTREAMER_H 95 | +#define LLVM_LIB_TARGET_RISCV_RISCVELFSTREAMER_H 96 | + 97 | +#include "RISCVTargetStreamer.h" 98 | +#include "llvm/MC/MCELFStreamer.h" 99 | + 100 | +namespace llvm { 101 | + 102 | +class RISCVTargetELFStreamer : public RISCVTargetStreamer { 103 | +public: 104 | + MCELFStreamer &getStreamer(); 105 | + RISCVTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); 106 | +}; 107 | +} 108 | +#endif 109 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp 110 | index f9a69826e10..ad35f8c4d9e 100644 111 | --- a/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp 112 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp 113 | @@ -13,7 +13,9 @@ 114 | 115 | #include "RISCVMCTargetDesc.h" 116 | #include "InstPrinter/RISCVInstPrinter.h" 117 | +#include "RISCVELFStreamer.h" 118 | #include "RISCVMCAsmInfo.h" 119 | +#include "RISCVTargetStreamer.h" 120 | #include "llvm/ADT/STLExtras.h" 121 | #include "llvm/MC/MCAsmInfo.h" 122 | #include "llvm/MC/MCInstrInfo.h" 123 | @@ -71,6 +73,14 @@ static MCInstPrinter *createRISCVMCInstPrinter(const Triple &T, 124 | return new RISCVInstPrinter(MAI, MII, MRI); 125 | } 126 | 127 | +static MCTargetStreamer * 128 | +createRISCVObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { 129 | + const Triple &TT = STI.getTargetTriple(); 130 | + if (TT.isOSBinFormatELF()) 131 | + return new RISCVTargetELFStreamer(S, STI); 132 | + return new RISCVTargetStreamer(S); 133 | +} 134 | + 135 | extern "C" void LLVMInitializeRISCVTargetMC() { 136 | for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) { 137 | TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo); 138 | @@ -80,5 +90,7 @@ extern "C" void LLVMInitializeRISCVTargetMC() { 139 | TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter); 140 | TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter); 141 | TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo); 142 | + TargetRegistry::RegisterObjectTargetStreamer( 143 | + *T, createRISCVObjectTargetStreamer); 144 | } 145 | } 146 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp 147 | new file mode 100644 148 | index 00000000000..e72b0243b2e 149 | --- /dev/null 150 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp 151 | @@ -0,0 +1,18 @@ 152 | +//===-- RISCVTargetStreamer.cpp - RISCV Target Streamer Methods -----------===// 153 | +// 154 | +// The LLVM Compiler Infrastructure 155 | +// 156 | +// This file is distributed under the University of Illinois Open Source 157 | +// License. See LICENSE.TXT for details. 158 | +// 159 | +//===----------------------------------------------------------------------===// 160 | +// 161 | +// This file provides RISCV specific target streamer methods. 162 | +// 163 | +//===----------------------------------------------------------------------===// 164 | + 165 | +#include "RISCVTargetStreamer.h" 166 | + 167 | +using namespace llvm; 168 | + 169 | +RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} 170 | diff --git a/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h 171 | new file mode 100644 172 | index 00000000000..3f395405b59 173 | --- /dev/null 174 | +++ b/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h 175 | @@ -0,0 +1,22 @@ 176 | +//===-- RISCVTargetStreamer.h - RISCV Target Streamer ----------*- C++ -*--===// 177 | +// 178 | +// The LLVM Compiler Infrastructure 179 | +// 180 | +// This file is distributed under the University of Illinois Open Source 181 | +// License. See LICENSE.TXT for details. 182 | +// 183 | +//===----------------------------------------------------------------------===// 184 | + 185 | +#ifndef LLVM_LIB_TARGET_RISCV_RISCVTARGETSTREAMER_H 186 | +#define LLVM_LIB_TARGET_RISCV_RISCVTARGETSTREAMER_H 187 | + 188 | +#include "llvm/MC/MCStreamer.h" 189 | + 190 | +namespace llvm { 191 | + 192 | +class RISCVTargetStreamer : public MCTargetStreamer { 193 | +public: 194 | + RISCVTargetStreamer(MCStreamer &S); 195 | +}; 196 | +} 197 | +#endif 198 | diff --git a/test/MC/RISCV/elf-flags.s b/test/MC/RISCV/elf-flags.s 199 | new file mode 100644 200 | index 00000000000..1d183aab339 201 | --- /dev/null 202 | +++ b/test/MC/RISCV/elf-flags.s 203 | @@ -0,0 +1,13 @@ 204 | +# RUN: llvm-mc -triple=riscv32 -filetype=obj < %s | llvm-readobj -file-headers - | FileCheck -check-prefixes=CHECK-RVI %s 205 | +# RUN: llvm-mc -triple=riscv64 -filetype=obj < %s | llvm-readobj -file-headers - | FileCheck -check-prefixes=CHECK-RVI %s 206 | +# RUN: llvm-mc -triple=riscv32 -mattr=+c -filetype=obj < %s | llvm-readobj -file-headers - | FileCheck -check-prefixes=CHECK-RVIC %s 207 | +# RUN: llvm-mc -triple=riscv64 -mattr=+c -filetype=obj < %s | llvm-readobj -file-headers - | FileCheck -check-prefixes=CHECK-RVIC %s 208 | + 209 | +# CHECK-RVI: Flags [ (0x0) 210 | +# CHECK-RVI-NEXT: ] 211 | + 212 | +# CHECK-RVIC: Flags [ (0x1) 213 | +# CHECK-RVIC-NEXT: EF_RISCV_RVC (0x1) 214 | +# CHECK-RVIC-NEXT: ] 215 | + 216 | +nop 217 | -- 218 | 2.16.2 219 | 220 | -------------------------------------------------------------------------------- /0032-RISCV-Reserve-an-emergency-spill-slot-for-the-regist.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Alex Bradbury 3 | Subject: [RISCV] Reserve an emergency spill slot for the register scavenger 4 | when necessary 5 | 6 | --- 7 | lib/Target/RISCV/RISCVFrameLowering.cpp | 19 +++++++ 8 | lib/Target/RISCV/RISCVFrameLowering.h | 3 + 9 | test/CodeGen/RISCV/large-stack.ll | 99 ++++++++++++++++++++++++++++++--- 10 | 3 files changed, 114 insertions(+), 7 deletions(-) 11 | 12 | diff --git a/lib/Target/RISCV/RISCVFrameLowering.cpp b/lib/Target/RISCV/RISCVFrameLowering.cpp 13 | index 85a354d0c12..32ed896bc98 100644 14 | --- a/lib/Target/RISCV/RISCVFrameLowering.cpp 15 | +++ b/lib/Target/RISCV/RISCVFrameLowering.cpp 16 | @@ -18,6 +18,7 @@ 17 | #include "llvm/CodeGen/MachineFunction.h" 18 | #include "llvm/CodeGen/MachineInstrBuilder.h" 19 | #include "llvm/CodeGen/MachineRegisterInfo.h" 20 | +#include "llvm/CodeGen/RegisterScavenging.h" 21 | 22 | using namespace llvm; 23 | 24 | @@ -224,3 +225,21 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, 25 | SavedRegs.set(RISCV::X1); 26 | SavedRegs.set(RISCV::X8); 27 | } 28 | + 29 | +void RISCVFrameLowering::processFunctionBeforeFrameFinalized( 30 | + MachineFunction &MF, RegScavenger *RS) const { 31 | + const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); 32 | + MachineFrameInfo &MFI = MF.getFrameInfo(); 33 | + const TargetRegisterClass *RC = &RISCV::GPRRegClass; 34 | + // estimateStackSize has been observed to under-estimate the final stack 35 | + // size, so give ourselves wiggle-room by checking for stack size 36 | + // representable an 11-bit signed field rather than 12-bits. 37 | + // FIXME: It may be possible to craft a function with a small stack that 38 | + // still needs an emergency spill slot for branch relaxation. This case 39 | + // would currently be missed. 40 | + if (!isInt<11>(MFI.estimateStackSize(MF))) { 41 | + int RegScavFI = MFI.CreateStackObject( 42 | + RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); 43 | + RS->addScavengingFrameIndex(RegScavFI); 44 | + } 45 | +} 46 | diff --git a/lib/Target/RISCV/RISCVFrameLowering.h b/lib/Target/RISCV/RISCVFrameLowering.h 47 | index d92bb70c76d..ccf7e247b55 100644 48 | --- a/lib/Target/RISCV/RISCVFrameLowering.h 49 | +++ b/lib/Target/RISCV/RISCVFrameLowering.h 50 | @@ -36,6 +36,9 @@ public: 51 | void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, 52 | RegScavenger *RS) const override; 53 | 54 | + void processFunctionBeforeFrameFinalized(MachineFunction &MF, 55 | + RegScavenger *RS) const override; 56 | + 57 | bool hasFP(const MachineFunction &MF) const override; 58 | 59 | MachineBasicBlock::iterator 60 | diff --git a/test/CodeGen/RISCV/large-stack.ll b/test/CodeGen/RISCV/large-stack.ll 61 | index cecca220e19..d3b429022a4 100644 62 | --- a/test/CodeGen/RISCV/large-stack.ll 63 | +++ b/test/CodeGen/RISCV/large-stack.ll 64 | @@ -8,31 +8,116 @@ define void @test() nounwind { 65 | ; RV32I-LABEL: test: 66 | ; RV32I: # %bb.0: 67 | ; RV32I-NEXT: lui a0, 74565 68 | -; RV32I-NEXT: addi a0, a0, 1664 69 | +; RV32I-NEXT: addi a0, a0, 1680 70 | ; RV32I-NEXT: sub sp, sp, a0 71 | ; RV32I-NEXT: lui a0, 74565 72 | -; RV32I-NEXT: addi a0, a0, 1660 73 | +; RV32I-NEXT: addi a0, a0, 1676 74 | ; RV32I-NEXT: add a0, sp, a0 75 | ; RV32I-NEXT: sw ra, 0(a0) 76 | ; RV32I-NEXT: lui a0, 74565 77 | -; RV32I-NEXT: addi a0, a0, 1656 78 | +; RV32I-NEXT: addi a0, a0, 1672 79 | ; RV32I-NEXT: add a0, sp, a0 80 | ; RV32I-NEXT: sw s0, 0(a0) 81 | ; RV32I-NEXT: lui a0, 74565 82 | -; RV32I-NEXT: addi a0, a0, 1664 83 | +; RV32I-NEXT: addi a0, a0, 1680 84 | ; RV32I-NEXT: add s0, sp, a0 85 | ; RV32I-NEXT: lui a0, 74565 86 | -; RV32I-NEXT: addi a0, a0, 1656 87 | +; RV32I-NEXT: addi a0, a0, 1672 88 | ; RV32I-NEXT: add a0, sp, a0 89 | ; RV32I-NEXT: lw s0, 0(a0) 90 | ; RV32I-NEXT: lui a0, 74565 91 | -; RV32I-NEXT: addi a0, a0, 1660 92 | +; RV32I-NEXT: addi a0, a0, 1676 93 | ; RV32I-NEXT: add a0, sp, a0 94 | ; RV32I-NEXT: lw ra, 0(a0) 95 | ; RV32I-NEXT: lui a0, 74565 96 | -; RV32I-NEXT: addi a0, a0, 1664 97 | +; RV32I-NEXT: addi a0, a0, 1680 98 | ; RV32I-NEXT: add sp, sp, a0 99 | ; RV32I-NEXT: jalr zero, ra, 0 100 | %tmp = alloca [ 305419896 x i8 ] , align 4 101 | ret void 102 | } 103 | + 104 | +; This test case artificially produces register pressure which should force 105 | +; use of the emergency spill slot. 106 | + 107 | +define void @test_emergency_spill_slot(i32 %a) nounwind { 108 | +; RV32I-LABEL: test_emergency_spill_slot: 109 | +; RV32I: # %bb.0: 110 | +; RV32I-NEXT: lui a1, 98 111 | +; RV32I-NEXT: addi a1, a1, -1376 112 | +; RV32I-NEXT: sub sp, sp, a1 113 | +; RV32I-NEXT: lui a1, 98 114 | +; RV32I-NEXT: addi a1, a1, -1380 115 | +; RV32I-NEXT: add a1, sp, a1 116 | +; RV32I-NEXT: sw ra, 0(a1) 117 | +; RV32I-NEXT: lui a1, 98 118 | +; RV32I-NEXT: addi a1, a1, -1384 119 | +; RV32I-NEXT: add a1, sp, a1 120 | +; RV32I-NEXT: sw s0, 0(a1) 121 | +; RV32I-NEXT: lui a1, 98 122 | +; RV32I-NEXT: addi a1, a1, -1388 123 | +; RV32I-NEXT: add a1, sp, a1 124 | +; RV32I-NEXT: sw s1, 0(a1) 125 | +; RV32I-NEXT: lui a1, 98 126 | +; RV32I-NEXT: addi a1, a1, -1392 127 | +; RV32I-NEXT: add a1, sp, a1 128 | +; RV32I-NEXT: sw s2, 0(a1) 129 | +; RV32I-NEXT: lui a1, 98 130 | +; RV32I-NEXT: addi a1, a1, -1376 131 | +; RV32I-NEXT: add s0, sp, a1 132 | +; RV32I-NEXT: lui a1, 78 133 | +; RV32I-NEXT: addi a1, a1, 512 134 | +; RV32I-NEXT: lui a2, 1048478 135 | +; RV32I-NEXT: addi a2, a2, 1388 136 | +; RV32I-NEXT: add a2, s0, a2 137 | +; RV32I-NEXT: addi a2, a2, 0 138 | +; RV32I-NEXT: add a1, a2, a1 139 | +; RV32I-NEXT: #APP 140 | +; RV32I-NEXT: nop 141 | +; RV32I-NEXT: #NO_APP 142 | +; RV32I-NEXT: sw a0, 0(a1) 143 | +; RV32I-NEXT: #APP 144 | +; RV32I-NEXT: nop 145 | +; RV32I-NEXT: #NO_APP 146 | +; RV32I-NEXT: lui a0, 98 147 | +; RV32I-NEXT: addi a0, a0, -1392 148 | +; RV32I-NEXT: add a0, sp, a0 149 | +; RV32I-NEXT: lw s2, 0(a0) 150 | +; RV32I-NEXT: lui a0, 98 151 | +; RV32I-NEXT: addi a0, a0, -1388 152 | +; RV32I-NEXT: add a0, sp, a0 153 | +; RV32I-NEXT: lw s1, 0(a0) 154 | +; RV32I-NEXT: lui a0, 98 155 | +; RV32I-NEXT: addi a0, a0, -1384 156 | +; RV32I-NEXT: add a0, sp, a0 157 | +; RV32I-NEXT: lw s0, 0(a0) 158 | +; RV32I-NEXT: lui a0, 98 159 | +; RV32I-NEXT: addi a0, a0, -1380 160 | +; RV32I-NEXT: add a0, sp, a0 161 | +; RV32I-NEXT: lw ra, 0(a0) 162 | +; RV32I-NEXT: lui a0, 98 163 | +; RV32I-NEXT: addi a0, a0, -1376 164 | +; RV32I-NEXT: add sp, sp, a0 165 | +; RV32I-NEXT: jalr zero, ra, 0 166 | + %data = alloca [ 100000 x i32 ] , align 4 167 | + %ptr = getelementptr inbounds [100000 x i32], [100000 x i32]* %data, i32 0, i32 80000 168 | + %1 = tail call { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } asm sideeffect "nop", "=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r"() 169 | + %asmresult0 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 0 170 | + %asmresult1 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 1 171 | + %asmresult2 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 2 172 | + %asmresult3 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 3 173 | + %asmresult4 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 4 174 | + %asmresult5 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 5 175 | + %asmresult6 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 6 176 | + %asmresult7 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 7 177 | + %asmresult8 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 8 178 | + %asmresult9 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 9 179 | + %asmresult10 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 10 180 | + %asmresult11 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 11 181 | + %asmresult12 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 12 182 | + %asmresult13 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 13 183 | + %asmresult14 = extractvalue { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 } %1, 14 184 | + store volatile i32 %a, i32* %ptr 185 | + tail call void asm sideeffect "nop", "r,r,r,r,r,r,r,r,r,r,r,r,r,r,r"(i32 %asmresult0, i32 %asmresult1, i32 %asmresult2, i32 %asmresult3, i32 %asmresult4, i32 %asmresult5, i32 %asmresult6, i32 %asmresult7, i32 %asmresult8, i32 %asmresult9, i32 %asmresult10, i32 %asmresult11, i32 %asmresult12, i32 %asmresult13, i32 %asmresult14) 186 | + ret void 187 | +} 188 | -- 189 | 2.16.2 190 | 191 | --------------------------------------------------------------------------------