├── 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 |
--------------------------------------------------------------------------------