mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 02:57:46 +00:00
compiler: handle nested unsigned shift being untyped after type resolution (#5497)
* apply compiler patch for fix of #5496 * add compiler/testdata smoketest * make diff error more explicit on difference * apply golden fix
This commit is contained in:
@@ -422,19 +422,19 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
|
||||
return c.ctx.Int8Type()
|
||||
case types.Int16, types.Uint16:
|
||||
return c.ctx.Int16Type()
|
||||
case types.Int32, types.Uint32:
|
||||
case types.Int32, types.Uint32, types.UntypedRune:
|
||||
return c.ctx.Int32Type()
|
||||
case types.Int, types.Uint:
|
||||
case types.Int, types.Uint, types.UntypedInt:
|
||||
return c.intType
|
||||
case types.Int64, types.Uint64:
|
||||
return c.ctx.Int64Type()
|
||||
case types.Float32:
|
||||
return c.ctx.FloatType()
|
||||
case types.Float64:
|
||||
case types.Float64, types.UntypedFloat:
|
||||
return c.ctx.DoubleType()
|
||||
case types.Complex64:
|
||||
return c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)
|
||||
case types.Complex128:
|
||||
case types.Complex128, types.UntypedComplex:
|
||||
return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)
|
||||
case types.String, types.UntypedString:
|
||||
return c.getLLVMRuntimeType("_string")
|
||||
|
||||
+50
-24
@@ -123,53 +123,79 @@ func TestCompiler(t *testing.T) {
|
||||
t.Fatal("failed to read golden file:", err)
|
||||
}
|
||||
|
||||
if !fuzzyEqualIR(mod.String(), string(expected)) {
|
||||
t.Errorf("output does not match expected output:\n%s", mod.String())
|
||||
if diff := diffIR(string(expected), mod.String()); diff != "" {
|
||||
t.Errorf("output does not match expected output (re-run with -update to regenerate):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fuzzyEqualIR returns true if the two LLVM IR strings passed in are roughly
|
||||
// equal. That means, only relevant lines are compared (excluding comments
|
||||
// etc.).
|
||||
func fuzzyEqualIR(s1, s2 string) bool {
|
||||
// normalizeIR canonicalizes LLVM IR so a single golden file keeps matching
|
||||
// across LLVM versions. Golden files are written against LLVM <21; newer LLVM
|
||||
// prints some attributes differently.
|
||||
func normalizeIR(s string) string {
|
||||
// Golden files are written using the pre-LLVM21 'nocapture' spelling,
|
||||
// which LLVM printed before any co-occurring attribute such as
|
||||
// 'readonly' (e.g. "ptr nocapture readonly"). LLVM 21+ prints the
|
||||
// equivalent 'captures(none)' instead, and after such attributes (e.g.
|
||||
// "ptr readonly captures(none)"). Normalize both name and position back
|
||||
// to the old spelling to keep a single golden file working across LLVM
|
||||
// versions.
|
||||
s1 = normalizeCapturesAttr(s1)
|
||||
s2 = normalizeCapturesAttr(s2)
|
||||
// to the old spelling.
|
||||
s = normalizeCapturesAttr(s)
|
||||
|
||||
// LLVM 21+ also added an explicit 'nocreateundeforpoison' attribute to
|
||||
// certain intrinsic declarations (e.g. llvm.umin) that were implicitly
|
||||
// assumed not to create undef/poison before. It's unrelated to the
|
||||
// behavior under test, so ignore it for comparison.
|
||||
s1 = strings.ReplaceAll(s1, "nocreateundeforpoison ", "")
|
||||
s2 = strings.ReplaceAll(s2, "nocreateundeforpoison ", "")
|
||||
s = strings.ReplaceAll(s, "nocreateundeforpoison ", "")
|
||||
|
||||
// LLVM 22 dropped the (redundant) i64 size argument from
|
||||
// llvm.lifetime.start/end. Normalize away that argument so golden files
|
||||
// written against the two-argument form still match.
|
||||
s1 = lifetimeSizeArgRe.ReplaceAllString(s1, "$1")
|
||||
s2 = lifetimeSizeArgRe.ReplaceAllString(s2, "$1")
|
||||
s = lifetimeSizeArgRe.ReplaceAllString(s, "$1")
|
||||
|
||||
lines1 := filterIrrelevantIRLines(strings.Split(s1, "\n"))
|
||||
lines2 := filterIrrelevantIRLines(strings.Split(s2, "\n"))
|
||||
if len(lines1) != len(lines2) {
|
||||
return false
|
||||
return s
|
||||
}
|
||||
|
||||
// diffIR compares two LLVM IR strings, ignoring irrelevant lines (comments,
|
||||
// empty lines, etc.) and normalizing LLVM-version-specific spellings via
|
||||
// normalizeIR. It returns "" when they are equal. Otherwise it returns a
|
||||
// compact diff of only the region that differs: the common prefix and suffix
|
||||
// are trimmed, then the differing expected lines (prefixed "-") are shown
|
||||
// followed by the differing actual lines (prefixed "+").
|
||||
func diffIR(expected, actual string) string {
|
||||
exp := filterIrrelevantIRLines(strings.Split(normalizeIR(expected), "\n"))
|
||||
act := filterIrrelevantIRLines(strings.Split(normalizeIR(actual), "\n"))
|
||||
|
||||
// Trim the common prefix.
|
||||
start := 0
|
||||
for start < len(exp) && start < len(act) && exp[start] == act[start] {
|
||||
start++
|
||||
}
|
||||
for i, line1 := range lines1 {
|
||||
line2 := lines2[i]
|
||||
if line1 != line2 {
|
||||
return false
|
||||
}
|
||||
// Trim the common suffix.
|
||||
e, a := len(exp), len(act)
|
||||
for e > start && a > start && exp[e-1] == act[a-1] {
|
||||
e--
|
||||
a--
|
||||
}
|
||||
if start == e && start == a {
|
||||
return "" // equal
|
||||
}
|
||||
|
||||
return true
|
||||
var b strings.Builder
|
||||
b.WriteString("first difference at relevant line ")
|
||||
b.WriteString(strconv.Itoa(start + 1))
|
||||
b.WriteString(":\n")
|
||||
for _, line := range exp[start:e] {
|
||||
b.WriteString("- ")
|
||||
b.WriteString(line)
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
for _, line := range act[start:a] {
|
||||
b.WriteString("+ ")
|
||||
b.WriteString(line)
|
||||
b.WriteByte('\n')
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// capturesNoneAttrRe matches a co-occurring attribute directly followed by
|
||||
|
||||
Vendored
+5
@@ -66,6 +66,11 @@ func complexSub(x, y complex64) complex64 {
|
||||
return x - y
|
||||
}
|
||||
|
||||
func shiftNested(x uint64) uint64 {
|
||||
k := 3
|
||||
return x >> (1 << k) // https://github.com/tinygo-org/tinygo/issues/5496
|
||||
}
|
||||
|
||||
func complexMul(x, y complex64) complex64 {
|
||||
return x * y
|
||||
}
|
||||
|
||||
Vendored
+7
@@ -176,6 +176,13 @@ entry:
|
||||
ret { float, float } %3
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i64 @main.shiftNested(i64 %x, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
%0 = lshr i64 %x, 8
|
||||
ret i64 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden { float, float } @main.complexMul(float %x.r, float %x.i, float %y.r, float %y.i, ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
|
||||
Reference in New Issue
Block a user