diff --git a/filetests/isa/riscv/encoding.cton b/filetests/isa/riscv/encoding.cton index 2ba06007bb..f6defe27bf 100644 --- a/filetests/isa/riscv/encoding.cton +++ b/filetests/isa/riscv/encoding.cton @@ -15,5 +15,7 @@ ebb0(v1: i32, v2: i32): ; check: [R#10c] ; sameln: $v12 = imul - return + return_reg v1 + ; check: [Iret#19] + ; sameln: return_reg } diff --git a/lib/cretonne/meta/isa/riscv/encodings.py b/lib/cretonne/meta/isa/riscv/encodings.py index 0fc3a3ee8d..bf84c468b0 100644 --- a/lib/cretonne/meta/isa/riscv/encodings.py +++ b/lib/cretonne/meta/isa/riscv/encodings.py @@ -4,7 +4,7 @@ RISC-V Encodings. from __future__ import absolute_import from base import instructions as base from .defs import RV32, RV64 -from .recipes import OPIMM, OPIMM32, OP, OP32, R, Rshamt, I +from .recipes import OPIMM, OPIMM32, OP, OP32, JALR, R, Rshamt, I, Iret from .settings import use_m # Basic arithmetic binary instructions are encoded in an R-type instruction. @@ -52,3 +52,12 @@ for inst, inst_imm, f3, f7 in [ RV32.enc(base.imul.i32, R, OP(0b000, 0b0000001), isap=use_m) RV64.enc(base.imul.i64, R, OP(0b000, 0b0000001), isap=use_m) RV64.enc(base.imul.i32, R, OP32(0b000, 0b0000001), isap=use_m) + +# Control flow. + +# Returns are a special case of JALR. +# Note: Return stack predictors will only recognize this as a return when the +# return address is provided in `x1`. We may want a special encoding to enforce +# that. +RV32.enc(base.return_reg.i32, Iret, JALR()) +RV64.enc(base.return_reg.i64, Iret, JALR()) diff --git a/lib/cretonne/meta/isa/riscv/recipes.py b/lib/cretonne/meta/isa/riscv/recipes.py index fe0618d6cc..ea7e019eb4 100644 --- a/lib/cretonne/meta/isa/riscv/recipes.py +++ b/lib/cretonne/meta/isa/riscv/recipes.py @@ -11,7 +11,7 @@ instruction formats described in the reference: from __future__ import absolute_import from cdsl.isa import EncRecipe from cdsl.predicates import IsSignedInt -from base.formats import Binary, BinaryImm +from base.formats import Binary, BinaryImm, ReturnReg from .registers import GPR # The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit @@ -40,6 +40,12 @@ def BRANCH(funct3): return 0b11000 | (funct3 << 5) +def JALR(funct3=0): + # type: (int) -> int + assert funct3 <= 0b111 + return 0b11001 | (funct3 << 5) + + def OPIMM(funct3, funct7=0): # type: (int, int) -> int assert funct3 <= 0b111 @@ -76,3 +82,8 @@ Rshamt = EncRecipe('Rshamt', BinaryImm, ins=GPR, outs=GPR) I = EncRecipe( 'I', BinaryImm, ins=GPR, outs=GPR, instp=IsSignedInt(BinaryImm.imm, 12)) + +# I-type encoding for `jalr` as a return instruction. We won't use the +# immediate offset. +# The variable return values are not encoded. +Iret = EncRecipe('Iret', ReturnReg, ins=GPR, outs=()) diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index 7a328a6d30..cb5fb8a24f 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -241,9 +241,9 @@ fn write_instruction(w: &mut Write, } ReturnReg { ref data, .. } => { if data.varargs.is_empty() { - writeln!(w, "{}", data.arg) + writeln!(w, " {}", data.arg) } else { - writeln!(w, "{}, {}", data.arg, data.varargs) + writeln!(w, " {}, {}", data.arg, data.varargs) } } } diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index 8651e09d4d..f44cfd4dc8 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -1327,9 +1327,12 @@ impl<'a> Parser<'a> { } } InstructionFormat::ReturnReg => { - let raddr = try!(self.match_value("expected SSA value return addr operand")); - try!(self.match_token(Token::Comma, "expected ',' between operands")); - let args = try!(self.parse_value_list()); + let raddr = try!(self.match_value("expected SSA value return address operand")); + let args = if self.optional(Token::Comma) { + try!(self.parse_value_list()) + } else { + VariableArgs::new() + }; InstructionData::ReturnReg { opcode: opcode, ty: VOID,