From 9212d453b052420e6d4a08dc6a9590cc126a7d0a Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Thu, 3 Nov 2016 20:49:09 -0700 Subject: [PATCH] cmd/internal/obj: sign extend 32-bit high immediate Bit 19 may be set in the high immediate returned by Split32BitImmediate. (The most obvious case is for 1<<31-1). This means that the immediate will be sign-extended when used with LUI. We must sign-extend this value to make it clear that this is intentional, otherwise assemble will reject the immediate for 'not fitting in 20 bits'. Fixes #10 Change-Id: I83ac8a81a5fb1a9663af63bc2dee8a896567f945 --- riscvtest/immediate.go | 21 +++++++++++++++++++++ riscvtest/run.go | 1 + src/cmd/internal/obj/riscv/asm.go | 30 ++++++++++++++++++++---------- 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 riscvtest/immediate.go diff --git a/riscvtest/immediate.go b/riscvtest/immediate.go new file mode 100644 index 00000000000000..ea949897c714e1 --- /dev/null +++ b/riscvtest/immediate.go @@ -0,0 +1,21 @@ +package main + +//go:noinline +func maxInt32() uint32 { + return 1<<31-1 +} + +func main() { + x := maxInt32() + if x != 1<<31-1 { + riscvexit(1) + } + + // Upper bits don't interfere in up-conversion. + y := uint64(maxInt32()) + uint64(maxInt32()) + if y != 1<<32-2 { + riscvexit(2) + } + + riscvexit(0) +} diff --git a/riscvtest/run.go b/riscvtest/run.go index 91d5e15aa83319..a5c0250355ac8f 100644 --- a/riscvtest/run.go +++ b/riscvtest/run.go @@ -42,6 +42,7 @@ var tests = [...]struct { {name: "global"}, {name: "live"}, {name: "typeswitch"}, + {name: "immediate"}, } func main() { diff --git a/src/cmd/internal/obj/riscv/asm.go b/src/cmd/internal/obj/riscv/asm.go index cc03a340752080..c0ff9cfa8e47f7 100644 --- a/src/cmd/internal/obj/riscv/asm.go +++ b/src/cmd/internal/obj/riscv/asm.go @@ -692,8 +692,24 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) { } } -// Split32BitImmediate splits a 32-bit immediate into a 20-bit upper immediate -// and a signed 12-bit lower immediate to be added to the upper result. +// signExtend sign extends val starting at bit bit. +func signExtend(val int64, bit uint) int64 { + // Mask off the bits to keep. + low := val + low &= 1<>= bit - 1 + val <<= 63 + val >>= 64 - bit + val |= low // put the low bits into place. + + return val +} + +// Split32BitImmediate splits a signed 32-bit immediate into a signed 20-bit +// upper immediate and a signed 12-bit lower immediate to be added to the upper +// result. // // For example, high may be used in LUI and low in a following ADDI to generate // a full 32-bit constant. @@ -721,14 +737,8 @@ func Split32BitImmediate(imm int64) (low, high int64, err error) { high++ } - // Generate our low 12 bit value. - lowBits := imm - lowBits &= 1<<12 - 1 // mask off the bits we just handled - // Generate upper sign bits, leaving space for the bottom 12 bits. - low = int64(lowBits >> 11) - low <<= 63 - low >>= 64 - 12 - low |= lowBits // put the low bits into place + high = signExtend(high, 20) + low = signExtend(imm, 12) return }