Skip to content

Commit cb6fe61

Browse files
committed
[Driver][DXC] Handle -Fo and -Fc flags
This splits the backend and assemble actions for HLSL inputs and handles the options in GetNamedOutputPath instead of aliasing `-o`. This also moves how we default to emitting asm to stdout, since doing this in the HLSL toolchain rather than the driver pollutes how the clang driver works as well. When both options are specified we disable collapsing the assemble action and attempt to generate both outputs. Note that while this handles the driver aspects, we can't actually run in that mode for now since -cc1as doesn't understand DXIL as an input yet. Differential Revision: https://reviews.llvm.org/D157582
1 parent e7866ea commit cb6fe61

File tree

9 files changed

+85
-22
lines changed

9 files changed

+85
-22
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8146,8 +8146,10 @@ class DXCJoinedOrSeparate<string name> : Option<["/", "-"], name,
81468146

81478147
def dxc_no_stdinc : DXCFlag<"hlsl-no-stdinc">,
81488148
HelpText<"HLSL only. Disables all standard includes containing non-native compiler types and functions.">;
8149-
def Fo : DXCJoinedOrSeparate<"Fo">, Alias<o>,
8149+
def dxc_Fo : DXCJoinedOrSeparate<"Fo">,
81508150
HelpText<"Output object file">;
8151+
def dxc_Fc : DXCJoinedOrSeparate<"Fc">,
8152+
HelpText<"Output assembly listing file">;
81518153
def dxil_validator_version : Option<["/", "-"], "validator-version", KIND_SEPARATE>,
81528154
Group<dxc_Group>, Flags<[NoXarchOption, HelpHidden]>,
81538155
Visibility<[DXCOption, ClangOption, CC1Option]>,

clang/include/clang/Driver/Types.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", phases
5454
TYPE("objc++-cpp-output", PP_ObjCXX_Alias, INVALID, "mii", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
5555
TYPE("objective-c++", ObjCXX, PP_ObjCXX, "mm", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
5656
TYPE("renderscript", RenderScript, PP_C, "rs", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
57-
TYPE("hlsl", HLSL, PP_CXX, "hlsl", phases::Preprocess, phases::Compile, phases::Backend)
57+
TYPE("hlsl", HLSL, PP_CXX, "hlsl", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble)
5858

5959
// C family input files to precompile.
6060
TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", phases::Precompile)

clang/include/clang/Driver/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace types {
4343

4444
/// getTypeTempSuffix - Return the suffix to use when creating a
4545
/// temp file of this type, or null if unspecified.
46-
const char *getTypeTempSuffix(ID Id, bool CLMode = false);
46+
const char *getTypeTempSuffix(ID Id, bool CLStyle = false);
4747

4848
/// onlyPrecompileType - Should this type only be precompiled.
4949
bool onlyPrecompileType(ID Id);

clang/lib/Driver/Driver.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,10 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
484484
DAL->append(A);
485485
}
486486

487+
// DXC mode quits before assembly if an output object file isn't specified.
488+
if (IsDXCMode() && !Args.hasArg(options::OPT_dxc_Fo))
489+
DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S));
490+
487491
// Enforce -static if -miamcu is present.
488492
if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false))
489493
DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_static));
@@ -5023,7 +5027,8 @@ class ToolSelector final {
50235027
return TC.useIntegratedAs() && !SaveTemps &&
50245028
!C.getArgs().hasArg(options::OPT_via_file_asm) &&
50255029
!C.getArgs().hasArg(options::OPT__SLASH_FA) &&
5026-
!C.getArgs().hasArg(options::OPT__SLASH_Fa);
5030+
!C.getArgs().hasArg(options::OPT__SLASH_Fa) &&
5031+
!C.getArgs().hasArg(options::OPT_dxc_Fc);
50275032
}
50285033

50295034
/// Return true if a preprocessor action can be collapsed.
@@ -5776,8 +5781,21 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
57765781
return "-";
57775782
}
57785783

5779-
if (IsDXCMode() && !C.getArgs().hasArg(options::OPT_o))
5780-
return "-";
5784+
if (JA.getType() == types::TY_PP_Asm &&
5785+
C.getArgs().hasArg(options::OPT_dxc_Fc)) {
5786+
StringRef FcValue = C.getArgs().getLastArgValue(options::OPT_dxc_Fc);
5787+
// TODO: Should we use `MakeCLOutputFilename` here? If so, we can probably
5788+
// handle this as part of the SLASH_Fa handling below.
5789+
return C.addResultFile(C.getArgs().MakeArgString(FcValue.str()), &JA);
5790+
}
5791+
5792+
if (JA.getType() == types::TY_Object &&
5793+
C.getArgs().hasArg(options::OPT_dxc_Fo)) {
5794+
StringRef FoValue = C.getArgs().getLastArgValue(options::OPT_dxc_Fo);
5795+
// TODO: Should we use `MakeCLOutputFilename` here? If so, we can probably
5796+
// handle this as part of the SLASH_Fo handling below.
5797+
return C.addResultFile(C.getArgs().MakeArgString(FoValue.str()), &JA);
5798+
}
57815799

57825800
// Is this the assembly listing for /FA?
57835801
if (JA.getType() == types::TY_PP_Asm &&
@@ -5791,6 +5809,11 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
57915809
&JA);
57925810
}
57935811

5812+
// DXC defaults to standard out when generating assembly. We check this after
5813+
// any DXC flags that might specify a file.
5814+
if (AtTopLevel && JA.getType() == types::TY_PP_Asm && IsDXCMode())
5815+
return "-";
5816+
57945817
bool SpecifiedModuleOutput =
57955818
C.getArgs().hasArg(options::OPT_fmodule_output) ||
57965819
C.getArgs().hasArg(options::OPT_fmodule_output_EQ);
@@ -5809,7 +5832,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
58095832
CCGenDiagnostics) {
58105833
StringRef Name = llvm::sys::path::filename(BaseInput);
58115834
std::pair<StringRef, StringRef> Split = Name.split('.');
5812-
const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
5835+
const char *Suffix =
5836+
types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode());
58135837
// The non-offloading toolchain on Darwin requires deterministic input
58145838
// file name for binaries to be deterministic, therefore it needs unique
58155839
// directory.
@@ -5900,7 +5924,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
59005924
NamedOutput =
59015925
MakeCLOutputFilename(C.getArgs(), Val, BaseName, types::TY_Object);
59025926
} else {
5903-
const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
5927+
const char *Suffix =
5928+
types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode());
59045929
assert(Suffix && "All types used for output should have a suffix.");
59055930

59065931
std::string::size_type End = std::string::npos;
@@ -5961,7 +5986,8 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
59615986
StringRef Name = llvm::sys::path::filename(BaseInput);
59625987
std::pair<StringRef, StringRef> Split = Name.split('.');
59635988
std::string TmpName = GetTemporaryPath(
5964-
Split.first, types::getTypeTempSuffix(JA.getType(), IsCLMode()));
5989+
Split.first,
5990+
types::getTypeTempSuffix(JA.getType(), IsCLMode() || IsDXCMode()));
59655991
return C.addTempFile(C.getArgs().MakeArgString(TmpName));
59665992
}
59675993
}

clang/lib/Driver/ToolChains/HLSL.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,6 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
229229
DAL->append(A);
230230
}
231231

232-
if (DAL->hasArg(options::OPT_o)) {
233-
// When run the whole pipeline.
234-
if (!DAL->hasArg(options::OPT_emit_llvm))
235-
// Emit obj if write to file.
236-
DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_obj));
237-
} else
238-
DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_o), "-");
239-
240232
// Add default validator version if not set.
241233
// TODO: remove this once read validator version from validator.
242234
if (!DAL->hasArg(options::OPT_dxil_validator_version)) {

clang/lib/Driver/Types.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ types::ID types::getPrecompiledType(ID Id) {
8080
return TY_INVALID;
8181
}
8282

83-
const char *types::getTypeTempSuffix(ID Id, bool CLMode) {
84-
if (CLMode) {
83+
const char *types::getTypeTempSuffix(ID Id, bool CLStyle) {
84+
if (CLStyle) {
8585
switch (Id) {
8686
case TY_Object:
8787
case TY_LTO_BC:

clang/test/Driver/dxc_dxv_path.hlsl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212

1313
// RUN: %clang_dxc -Tlib_6_3 -ccc-print-bindings --dxv-path=%T -Fo %t.dxo %s 2>&1 | FileCheck %s --check-prefix=BINDINGS
1414
// BINDINGS: "dxil-unknown-shadermodel6.3-library" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[DXC:.+]].dxo"
15-
// BINDINGS-NEXT: "dxil-unknown-shadermodel6.3-library" - "hlsl::Validator", inputs: ["[[DXC]].dxo"], output: "[[DXC]].dxo"
15+
// BINDINGS-NEXT: "dxil-unknown-shadermodel6.3-library" - "hlsl::Validator", inputs: ["[[DXC]].dxo"]
1616

1717
// RUN: %clang_dxc -Tlib_6_3 -ccc-print-phases --dxv-path=%T -Fo %t.dxc %s 2>&1 | FileCheck %s --check-prefix=PHASES
1818

1919
// PHASES: 0: input, "[[INPUT:.+]]", hlsl
2020
// PHASES-NEXT: 1: preprocessor, {0}, c++-cpp-output
2121
// PHASES-NEXT: 2: compiler, {1}, ir
2222
// PHASES-NEXT: 3: backend, {2}, assembler
23-
// PHASES-NEXT: 4: binary-analyzer, {3}, dx-container
23+
// PHASES-NEXT: 4: assembler, {3}, object
24+
// PHASES-NEXT: 5: binary-analyzer, {4}, dx-container

clang/test/Driver/dxc_output.hlsl

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// With no output args, we emit assembly to stdout.
2+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -### 2>&1 | FileCheck %s --check-prefixes=CHECK-CC1,CHECK-CC1-STDOUT
3+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -ccc-print-phases 2>&1 | FileCheck %s --check-prefixes=CHECK-PHASES,CHECK-PHASES-ASM
4+
5+
// Same if we explicitly ask for assembly (-Fc) to stdout.
6+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fc - -### 2>&1 | FileCheck %s --check-prefixes=CHECK-CC1,CHECK-CC1-STDOUT
7+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fc - -ccc-print-phases 2>&1 | FileCheck %s --check-prefixes=CHECK-PHASES,CHECK-PHASES-ASM
8+
9+
// DXIL Assembly to a file.
10+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fc x.asm -### 2>&1 | FileCheck %s --check-prefixes=CHECK-CC1,CHECK-CC1-ASM
11+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fcx.asm -### 2>&1 | FileCheck %s --check-prefixes=CHECK-CC1,CHECK-CC1-ASM
12+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fc x.asm -ccc-print-phases 2>&1 | FileCheck %s --check-prefixes=CHECK-PHASES,CHECK-PHASES-ASM
13+
14+
// DXIL Object code to a file.
15+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fo x.obj -### 2>&1 | FileCheck %s --check-prefixes=CHECK-CC1,CHECK-CC1-OBJ
16+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fox.obj -### 2>&1 | FileCheck %s --check-prefixes=CHECK-CC1,CHECK-CC1-OBJ
17+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fo x.obj -ccc-print-phases 2>&1 | FileCheck %s --check-prefixes=CHECK-PHASES,CHECK-PHASES-OBJ
18+
19+
// If both -Fc and -Fo are provided, we generate both files.
20+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fc x.asm -Fo x.obj -### 2>&1 | FileCheck %s --check-prefixes=CHECK-CC1,CHECK-CC1-ASM,CHECK-CC1-BOTH
21+
// RUN: %clang_dxc -T lib_6_7 -Vd %s -Fc x.asm -Fo x.obj -ccc-print-phases 2>&1 | FileCheck %s --check-prefixes=CHECK-PHASES,CHECK-PHASES-OBJ
22+
23+
// CHECK-PHASES: 0: input, {{.*}}, hlsl
24+
// CHECK-PHASES: 1: preprocessor, {0}, c++-cpp-output
25+
// CHECK-PHASES: 2: compiler, {1}, ir
26+
// CHECK-PHASES: 3: backend, {2}, assembler
27+
// CHECK-PHASES-ASM-NOT: 4: assembler, {3}, object
28+
// CHECK-PHASES-OBJ: 4: assembler, {3}, object
29+
30+
// CHECK-CC1: "-cc1"
31+
// CHECK-CC1-STDOUT-SAME: "-o" "-"
32+
33+
// CHECK-CC1-ASM-SAME: "-S"
34+
// CHECK-CC1-ASM-SAME: "-o" "x.asm"
35+
36+
// CHECK-CC1-OBJ-SAME: "-emit-obj"
37+
// CHECK-CC1-OBJ-SAME: "-o" "x.obj"
38+
39+
// For the case where we specify both -Fc and -Fo, we emit the asm as part of
40+
// cc1 and invoke cc1as for the object.
41+
// CHECK-CC1-BOTH: "-cc1as"
42+
// CHECK-CC1-BOTH-SAME: "-o" "x.obj"

llvm/lib/MC/MCParser/AsmParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
807807
PlatformParser.reset(createXCOFFAsmParser());
808808
break;
809809
case MCContext::IsDXContainer:
810-
llvm_unreachable("DXContainer is not supported yet");
810+
report_fatal_error("DXContainer is not supported yet");
811811
break;
812812
}
813813

0 commit comments

Comments
 (0)