Skip to content

Commit 9ce8512

Browse files
Merge branch 'master' into ci-add-sascha-willems
2 parents 452d787 + b389635 commit 9ce8512

File tree

6 files changed

+315
-30
lines changed

6 files changed

+315
-30
lines changed

prelude/slang-torch-prelude.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,20 +158,19 @@ TensorView make_tensor_view(
158158
.append(")")
159159
.c_str());
160160

161-
bool isEmpty = true;
161+
// A tensor can have zero elements even if some dimensions are non-zero
162+
// (e.g. shape (10, 0)). Emptiness must be based on numel().
163+
bool isEmpty = (val.numel() == 0);
162164
for (int i = 0; i < val.dim(); ++i)
163165
{
166+
res.sizes[i] = val.size(i);
164167
res.strides[i] = val.stride(i) * elementSize;
165-
if (res.strides[i] == 0)
168+
if (!isEmpty && res.strides[i] == 0)
166169
throw std::runtime_error(
167170
std::string(name)
168171
.append(": tensors with broadcasted dimensions are not supported (use "
169172
"tensor.contiguous() to make tensor whole)")
170173
.c_str());
171-
172-
res.sizes[i] = val.size(i);
173-
if (res.sizes[i] > 0)
174-
isEmpty = false;
175174
}
176175

177176
if (!res.data && !isEmpty)

source/compiler-core/slang-rich-diagnostics-render.cpp

Lines changed: 81 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct DiagnosticRenderer
134134
Int64 number = 0;
135135
UnownedStringSlice content;
136136
List<LineHighlight> spans;
137+
bool sourceAvailable = false;
137138
};
138139

139140
// A collection of nearby HighlightedLines
@@ -303,12 +304,13 @@ struct DiagnosticRenderer
303304
{
304305
HighlightedLine& line = grouped[span.line];
305306
line.number = span.line;
306-
if (line.content.getLength() == 0)
307+
if (line.content.getLength() == 0 && !line.sourceAvailable)
307308
{
308309
SourceView* view =
309310
m_sourceManager ? m_sourceManager->findSourceView(span.startLoc) : nullptr;
310311
if (view)
311312
{
313+
line.sourceAvailable = true;
312314
// Get the line content and trim end-of-line characters and trailing whitespace
313315
UnownedStringSlice rawLine = StringUtil::trimEndOfLine(
314316
view->getSourceFile()->getLineAtIndex(span.line - 1));
@@ -347,6 +349,18 @@ struct DiagnosticRenderer
347349
return section;
348350
}
349351

352+
// Returns true if any line in the section has source text available.
353+
// When source is unavailable (e.g. built-in modules), we skip rendering
354+
// the section body to avoid showing empty source lines with underlines.
355+
bool sectionHasSourceAvailable(const SectionLayout& section) const
356+
{
357+
for (const auto& block : section.blocks)
358+
for (const auto& line : block.lines)
359+
if (line.sourceAvailable)
360+
return true;
361+
return false;
362+
}
363+
350364
Int64 findCommonIndent(const List<LayoutBlock>& blocks)
351365
{
352366
Index minIndent = std::numeric_limits<Index>::max();
@@ -504,6 +518,24 @@ struct DiagnosticRenderer
504518
return rows;
505519
}
506520

521+
// When source text is unavailable (e.g. built-in modules), render span
522+
// labels with a compact gutter structure (pipe + closing corner), using a
523+
// minimal gutter width since there are no line numbers to display.
524+
void renderOrphanedLabels(StringBuilder& ss, const SectionLayout& section, Int64 gutterWidth)
525+
{
526+
String gutter =
527+
repeat(' ', gutterWidth + 1) + color(TerminalColor::Cyan, m_glyphs.vertical);
528+
for (const auto& block : section.blocks)
529+
for (const auto& line : block.lines)
530+
for (const auto& span : line.spans)
531+
if (span.label.getLength() > 0)
532+
ss << gutter << " " << color(TerminalColor::BoldRed, span.label) << "\n";
533+
ss << color(
534+
TerminalColor::Cyan,
535+
repeat(m_glyphs.secondaryUnderline, gutterWidth + 1) + m_glyphs.gutterCorner)
536+
<< "\n";
537+
}
538+
507539
void renderSectionBody(StringBuilder& ss, const SectionLayout& section)
508540
{
509541
for (const auto& block : section.blocks)
@@ -643,36 +675,61 @@ struct DiagnosticRenderer
643675
layout.primaryLoc.line > 0 || layout.primaryLoc.fileName.getLength() > 0;
644676
if (hasValidLocation)
645677
{
646-
renderLocation(ss, layout.primaryLoc);
647-
648-
if (layout.primarySection.blocks.getCount() > 0)
678+
bool primaryHasSource = sectionHasSourceAvailable(layout.primarySection);
679+
if (primaryHasSource)
680+
{
681+
renderLocation(ss, layout.primaryLoc);
682+
if (layout.primarySection.blocks.getCount() > 0)
683+
{
684+
ss << repeat(' ', layout.primarySection.maxGutterWidth + 1)
685+
<< color(TerminalColor::Cyan, m_glyphs.vertical) << "\n";
686+
renderSectionBody(ss, layout.primarySection);
687+
ss << color(
688+
TerminalColor::Cyan,
689+
repeat(
690+
m_glyphs.secondaryUnderline,
691+
layout.primarySection.maxGutterWidth + 1) +
692+
m_glyphs.gutterCorner)
693+
<< "\n";
694+
}
695+
}
696+
else
649697
{
650-
ss << repeat(' ', layout.primarySection.maxGutterWidth + 1)
651-
<< color(TerminalColor::Cyan, m_glyphs.vertical) << "\n";
652-
renderSectionBody(ss, layout.primarySection);
653-
ss << color(
654-
TerminalColor::Cyan,
655-
repeat(
656-
m_glyphs.secondaryUnderline,
657-
layout.primarySection.maxGutterWidth + 1) +
658-
m_glyphs.gutterCorner)
659-
<< "\n";
698+
constexpr Int64 kOrphanGutterWidth = 0;
699+
DiagnosticLayout::Location loc = layout.primaryLoc;
700+
loc.gutterIndent = kOrphanGutterWidth;
701+
renderLocation(ss, loc);
702+
if (layout.primarySection.blocks.getCount() > 0)
703+
renderOrphanedLabels(ss, layout.primarySection, kOrphanGutterWidth);
660704
}
661705
}
662706
for (const auto& note : layout.notes)
663707
{
664708
ss << "\n" << color(TerminalColor::Cyan, "note") << ": " << note.message << "\n";
665-
renderNoteLocation(ss, note.loc);
666-
if (note.section.blocks.getCount() > 0)
709+
bool noteHasSource = sectionHasSourceAvailable(note.section);
710+
if (noteHasSource)
711+
{
712+
renderNoteLocation(ss, note.loc);
713+
if (note.section.blocks.getCount() > 0)
714+
{
715+
ss << repeat(' ', note.section.maxGutterWidth + 1)
716+
<< color(TerminalColor::Cyan, m_glyphs.vertical) << "\n";
717+
renderSectionBody(ss, note.section);
718+
ss << color(
719+
TerminalColor::Cyan,
720+
repeat(m_glyphs.secondaryUnderline, note.section.maxGutterWidth + 1) +
721+
m_glyphs.gutterCorner)
722+
<< "\n";
723+
}
724+
}
725+
else
667726
{
668-
ss << repeat(' ', note.section.maxGutterWidth + 1)
669-
<< color(TerminalColor::Cyan, m_glyphs.vertical) << "\n";
670-
renderSectionBody(ss, note.section);
671-
ss << color(
672-
TerminalColor::Cyan,
673-
repeat(m_glyphs.secondaryUnderline, note.section.maxGutterWidth + 1) +
674-
m_glyphs.gutterCorner)
675-
<< "\n";
727+
constexpr Int64 kOrphanGutterWidth = 0;
728+
DiagnosticLayout::Location noteLoc = note.loc;
729+
noteLoc.gutterIndent = kOrphanGutterWidth;
730+
renderNoteLocation(ss, noteLoc);
731+
if (note.section.blocks.getCount() > 0)
732+
renderOrphanedLabels(ss, note.section, kOrphanGutterWidth);
676733
}
677734
}
678735
return ss.produceString();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//TEST:SIMPLE(diag=CHK):-target hlsl -stage compute -entry computeMain
2+
//TEST:SIMPLE(filecheck=FC):-target hlsl -stage compute -entry computeMain
3+
4+
// Test that diagnostics pointing to built-in modules (where source text is
5+
// unavailable) don't render empty source sections.
6+
7+
Texture2D<int4> t2D;
8+
SamplerState s;
9+
10+
RWStructuredBuffer<int4> outputBuffer;
11+
12+
void computeMain()
13+
{
14+
outputBuffer[0] = t2D.Sample(s, float2(0.0, 0.0));
15+
//CHK: static assertion failed
16+
//CHK: HLSL supports only float and half type textures
17+
//CHK: see call to 'Sample'
18+
}
19+
20+
// FC: error[E41400]: static assertion failed
21+
// FC-NEXT: --> hlsl.meta.slang:{{[0-9]+}}:{{[0-9]+}}
22+
// FC-NEXT: | static assertion failed, HLSL supports only float and half type textures
23+
// FC-NEXT: -'
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Explicitly specializing a constrained generic function with an
2+
// interface type should be rejected with the same diagnostic as
3+
// implicit inference (error 33180). Currently crashes with an
4+
// internal compiler error (99999) on a different code path than
5+
// the implicit case in diagnose-generic-func-with-interface.slang.
6+
7+
// Disabled: ICE -- should emit error 33180 but crashes with error 99999
8+
//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target spirv
9+
//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage compute -entry computeMain
10+
//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target glsl -stage compute -entry computeMain
11+
//DISABLE_TEST:SIMPLE(filecheck=CHECK): -target metal -stage compute -entry computeMain
12+
13+
#lang slang 2025
14+
15+
interface IFoo
16+
{
17+
float calc(float x);
18+
}
19+
20+
struct A : IFoo
21+
{
22+
float calc(float x) { return x * x; }
23+
}
24+
25+
struct B : IFoo
26+
{
27+
float calc(float x) { return x * 2; }
28+
}
29+
30+
float genericFunc<T : IFoo>(T obj, float x)
31+
{
32+
return obj.calc(x);
33+
}
34+
35+
IFoo makeInterface(uint id)
36+
{
37+
if (id == 0)
38+
return A();
39+
else
40+
return B();
41+
}
42+
43+
RWStructuredBuffer<float> outputBuffer;
44+
45+
[numthreads(1, 1, 1)]
46+
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
47+
{
48+
IFoo obj = makeInterface(dispatchThreadID.x);
49+
50+
// Explicit specialization with an interface type should be rejected
51+
// the same way implicit inference is (error 33180).
52+
// CHECK: ([[# @LINE+1]]): error[E33180]
53+
float result = genericFunc<IFoo>(obj, 3.0);
54+
55+
outputBuffer[0] = result;
56+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// A generic method in a struct, constrained with T : IFoo, correctly
2+
// dispatches when called with an interface-typed argument. This works
3+
// even though free generic functions with the same constraint produce
4+
// error 33180.
5+
6+
//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-slang -compute -shaderobj -output-using-type
7+
//TEST(compute,vulkan):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-vk -compute -shaderobj -output-using-type
8+
//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-cuda -compute -shaderobj -output-using-type
9+
//TEST(compute):COMPARE_COMPUTE_EX(filecheck-buffer=CHECK):-cpu -compute -shaderobj -output-using-type
10+
//TEST:SIMPLE(filecheck=REPORT):-target hlsl -stage compute -entry computeMain -report-dynamic-dispatch-sites
11+
12+
interface IFoo
13+
{
14+
float calc(float x);
15+
}
16+
17+
struct FooA : IFoo
18+
{
19+
float calc(float x) { return x * 2.0; }
20+
}
21+
22+
struct FooB : IFoo
23+
{
24+
float calc(float x) { return x + 10.0; }
25+
}
26+
27+
struct Processor
28+
{
29+
float scale;
30+
31+
float apply<T : IFoo>(T obj, float x)
32+
{
33+
return obj.calc(x) * scale;
34+
// REPORT-DAG: note[E50102]: generated {{.*}} dispatch code{{.*}} 2 possible types:
35+
}
36+
}
37+
38+
IFoo makeObj(int id)
39+
{
40+
if (id == 0) return FooA();
41+
else return FooB();
42+
}
43+
44+
float testGenericMethod(int id, float x, float scale)
45+
{
46+
IFoo obj = makeObj(id);
47+
Processor p;
48+
p.scale = scale;
49+
return p.apply(obj, x);
50+
}
51+
52+
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
53+
RWStructuredBuffer<float> outputBuffer;
54+
55+
[numthreads(1, 1, 1)]
56+
void computeMain(int id : SV_DispatchThreadID)
57+
{
58+
// FooA: calc(5.0) * 2.0 = 10.0 * 2.0 = 20.0
59+
outputBuffer[0] = testGenericMethod(id, 5.0, 2.0);
60+
// CHECK: 20.0
61+
62+
// FooB: calc(5.0) * 2.0 = 15.0 * 2.0 = 30.0
63+
outputBuffer[1] = testGenericMethod(id + 1, 5.0, 2.0);
64+
// CHECK: 30.0
65+
66+
// FooA: calc(3.0) * 0.5 = 6.0 * 0.5 = 3.0
67+
outputBuffer[2] = testGenericMethod(id, 3.0, 0.5);
68+
// CHECK: 3.0
69+
70+
// FooB: calc(3.0) * 0.5 = 13.0 * 0.5 = 6.5
71+
outputBuffer[3] = testGenericMethod(id + 1, 3.0, 0.5);
72+
// CHECK: 6.5
73+
}

0 commit comments

Comments
 (0)