Skip to content

Commit

Permalink
cmd/internal/obj: sign extend 32-bit high immediate
Browse files Browse the repository at this point in the history
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 golang#10

Change-Id: I83ac8a81a5fb1a9663af63bc2dee8a896567f945
  • Loading branch information
prattmic committed Nov 4, 2016
1 parent 0619b7b commit 9212d45
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
21 changes: 21 additions & 0 deletions riscvtest/immediate.go
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions riscvtest/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ var tests = [...]struct {
{name: "global"},
{name: "live"},
{name: "typeswitch"},
{name: "immediate"},
}

func main() {
Expand Down
30 changes: 20 additions & 10 deletions src/cmd/internal/obj/riscv/asm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

// Generate upper sign bits, leaving space for the bottom bits.
val >>= 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.
Expand Down Expand Up @@ -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
}
Expand Down

0 comments on commit 9212d45

Please sign in to comment.