Skip to content

Commit

Permalink
Add debug.printf dxil intrinsic support
Browse files Browse the repository at this point in the history
Add debug.printf dxil intrinsic, the dxil opcode is 258
  • Loading branch information
jiaolu committed Sep 6, 2024
1 parent 663785a commit a48593a
Show file tree
Hide file tree
Showing 12 changed files with 211 additions and 31 deletions.
9 changes: 5 additions & 4 deletions docs/DXIL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ The following values of ``<shaderModelName>``, ``<major>``, ``<minor>`` are supp
+===========================+==============================+======================+
| Vertex shader (VS) | vs | 6, 0 |
+---------------------------+------------------------------+----------------------+
| Hull shader (HS) | hs | 6, 0 |
| Hull shader (HS) | hs | 6, 0 |
+---------------------------+------------------------------+----------------------+
| Domain shader (DS) | ds | 6, 0 |
| Domain shader (DS) | ds | 6, 0 |
+---------------------------+------------------------------+----------------------+
| Geometry shader (GS) | gs | 6, 0 |
| Geometry shader (GS) | gs | 6, 0 |
+---------------------------+------------------------------+----------------------+
| Pixel shader (PS) | ps | 6, 0 |
| Pixel shader (PS) | ps | 6, 0 |
+---------------------------+------------------------------+----------------------+
| Compute shader (CS) | cs | 6, 0 |
+---------------------------+------------------------------+----------------------+
Expand Down Expand Up @@ -2369,6 +2369,7 @@ ID Name Description
255 SampleCmpBias samples a texture after applying the input bias to the mipmap level and compares a single component against the specified comparison value
256 StartVertexLocation returns the BaseVertexLocation from DrawIndexedInstanced or StartVertexLocation from DrawInstanced
257 StartInstanceLocation returns the StartInstanceLocation from Draw*Instanced
258 DebugPrintf create a c/c++ like printf function intrinsic
=== ===================================================== =======================================================================================================================================================================================================================


Expand Down
14 changes: 10 additions & 4 deletions include/dxc/DXIL/DxilConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@ enum class OpCode : unsigned {
IndexNodeHandle = 248, // returns the handle for the location in the output
// node array at the indicated index

// Debug info
DebugPrintf = 258, // printf like intrinsic

// Derivatives
CalculateLOD = 81, // calculates the level of detail
DerivCoarseX = 83, // computes the rate of change per stamp in x direction.
Expand Down Expand Up @@ -983,9 +986,9 @@ enum class OpCode : unsigned {
NumOpCodes_Dxil_1_5 = 216,
NumOpCodes_Dxil_1_6 = 222,
NumOpCodes_Dxil_1_7 = 226,
NumOpCodes_Dxil_1_8 = 258,
NumOpCodes_Dxil_1_8 = 259,

NumOpCodes = 258 // exclusive last value of enumeration
NumOpCodes = 259 // exclusive last value of enumeration
};
// OPCODE-ENUM:END

Expand Down Expand Up @@ -1041,6 +1044,9 @@ enum class OpCodeClass : unsigned {
IndexNodeHandle,
createNodeOutputHandle,

// Debug info
DebugPrintf,

// Derivatives
CalculateLOD,
Unary,
Expand Down Expand Up @@ -1290,9 +1296,9 @@ enum class OpCodeClass : unsigned {
NumOpClasses_Dxil_1_5 = 143,
NumOpClasses_Dxil_1_6 = 149,
NumOpClasses_Dxil_1_7 = 153,
NumOpClasses_Dxil_1_8 = 174,
NumOpClasses_Dxil_1_8 = 175,

NumOpClasses = 174 // exclusive last value of enumeration
NumOpClasses = 175 // exclusive last value of enumeration
};
// OPCODECLASS-ENUM:END

Expand Down
15 changes: 15 additions & 0 deletions include/dxc/DXIL/DxilInstructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -8765,5 +8765,20 @@ struct DxilInst_StartInstanceLocation {
// Metadata
bool requiresUniformInputs() const { return false; }
};

/// This instruction printf like intrinsic
struct DxilInst_DebugPrintf {
llvm::Instruction *Instr;
// Construction and identification
DxilInst_DebugPrintf(llvm::Instruction *pInstr) : Instr(pInstr) {}
operator bool() const {
return hlsl::OP::IsDxilOpFuncCallInst(Instr, hlsl::OP::OpCode::DebugPrintf);
}
// Validation support
bool isAllowed() const { return true; }
bool isArgumentListValid() const { return true; }
// Metadata
bool requiresUniformInputs() const { return false; }
};
// INSTR-HELPER:END
} // namespace hlsl
4 changes: 3 additions & 1 deletion include/dxc/DXIL/DxilOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ class OP {
// caches.
void RefreshCache();

llvm::Function *GetOpFunc(OpCode OpCode, llvm::Type *pOverloadType);
llvm::Function *GetOpFunc(OpCode OpCode, llvm::Type *pOverloadType,
llvm::ArrayRef<llvm::Type *> VarArgs = {});
const llvm::SmallMapVector<llvm::Type *, llvm::Function *, 8> &
GetOpFuncList(OpCode OpCode) const;
bool IsDxilOpUsed(OpCode opcode) const;
Expand Down Expand Up @@ -139,6 +140,7 @@ class OP {
bool bWithTranslation, unsigned valMajor,
unsigned valMinor, unsigned &major,
unsigned &minor, unsigned &mask);
static bool IsDxilOpVarArg(OpCode C);

private:
// Per-module properties.
Expand Down
4 changes: 2 additions & 2 deletions include/llvm/IR/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class Value {
using difference_type = std::ptrdiff_t;
using pointer = value_type *;
using reference = value_type &;

user_iterator_impl() {}

bool operator==(const user_iterator_impl &x) const { return UI == x.UI; }
Expand Down Expand Up @@ -532,7 +532,7 @@ class Value {

return Merged;
}

/// \brief Tail-recursive helper for \a mergeUseLists().
///
/// \param[out] Next the first element in the list.
Expand Down
41 changes: 38 additions & 3 deletions lib/DXIL/DxilOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2602,6 +2602,18 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = {
false},
Attribute::ReadNone,
},

// Debug info void, h, f, d, i1, i8, i16, i32, i64,
// udt, obj , function attribute
{
OC::DebugPrintf,
"DebugPrintf",
OCC::DebugPrintf,
"debugPrintf",
{true, false, false, false, false, false, false, false, false, false,
false},
Attribute::ArgMemOnly,
},
};
// OPCODE-OLOADS:END

Expand Down Expand Up @@ -2737,6 +2749,12 @@ bool OP::IsOverloadLegal(OpCode opCode, Type *pType) {
m_OpCodeProps[(unsigned)opCode].bAllowOverload[TypeSlot];
}

bool OP::IsDxilOpVarArg(OpCode opCode) {
if (opCode == OpCode::DebugPrintf)
return true;
return false;
}

bool OP::CheckOpCodeTable() {
for (unsigned i = 0; i < (unsigned)OpCode::NumOpCodes; i++) {
if ((unsigned)m_OpCodeProps[i].opCode != i)
Expand Down Expand Up @@ -3533,7 +3551,8 @@ void OP::UpdateCache(OpCodeClass opClass, Type *Ty, llvm::Function *F) {
m_FunctionToOpClass[F] = opClass;
}

Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType,
ArrayRef<Type *> VarArgTypes) {
if (opCode == OpCode::NumOpCodes)
return nullptr;
if (!pOverloadType)
Expand Down Expand Up @@ -5421,6 +5440,12 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
A(pI32);
A(pI32);
break;

// Debug info
case OpCode::DebugPrintf:
A(pV);
A(pI32);
break;
// OPCODE-OLOAD-FUNCS:END
default:
DXASSERT(false, "otherwise unhandled case");
Expand All @@ -5429,10 +5454,19 @@ Function *OP::GetOpFunc(OpCode opCode, Type *pOverloadType) {
#undef RRT
#undef A

bool isVarArg = VarArgTypes.size() > 0;
if (!isVarArg) {
if (opCode == OpCode::DebugPrintf)
return nullptr;
VarArgTypes = ArgTypes;
}

FunctionType *pFT;
DXASSERT(ArgTypes.size() > 1, "otherwise forgot to initialize arguments");
DXASSERT(VarArgTypes.size() > 1, "otherwise forgot to initialize arguments");

pFT = FunctionType::get(
ArgTypes[0], ArrayRef<Type *>(&ArgTypes[1], ArgTypes.size() - 1), false);
VarArgTypes[0], ArrayRef<Type *>(&VarArgTypes[1], VarArgTypes.size() - 1),
isVarArg);

std::string funcName;
ConstructOverloadName(pOverloadType, opCode, funcName);
Expand Down Expand Up @@ -5679,6 +5713,7 @@ llvm::Type *OP::GetOverloadType(OpCode opCode, llvm::Function *F) {
case OpCode::AnnotateNodeRecordHandle:
case OpCode::NodeOutputIsValid:
case OpCode::GetRemainingRecursionLevels:
case OpCode::DebugPrintf:
return Type::getVoidTy(Ctx);
case OpCode::CheckAccessFullyMapped:
case OpCode::SampleIndex:
Expand Down
7 changes: 5 additions & 2 deletions lib/DxilValidation/DxilValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1990,7 +1990,10 @@ static void ValidateExternalFunction(Function *F, ValidationContext &ValCtx) {
// In some cases, no overloads are provided (void is exclusive to others)
Function *dxilFunc;
if (hlslOP->IsOverloadLegal(dxilOpcode, voidTy)) {
dxilFunc = hlslOP->GetOpFunc(dxilOpcode, voidTy);
if (hlslOP->IsDxilOpVarArg(dxilOpcode))
dxilFunc = CI->getCalledFunction();
else
dxilFunc = hlslOP->GetOpFunc(dxilOpcode, voidTy);
} else {
Type *Ty = OP::GetOverloadType(dxilOpcode, CI->getCalledFunction());
try {
Expand Down Expand Up @@ -2706,7 +2709,7 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {

bool IllegalOpFunc = true;
for (auto &it : hlslOP->GetOpFuncList(dxilOpcode)) {
if (it.second == FCalled) {
if (it.second == FCalled || hlslOP->IsDxilOpVarArg(dxilOpcode)) {
IllegalOpFunc = false;
break;
}
Expand Down
111 changes: 105 additions & 6 deletions lib/HLSL/HLOperationLower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@
#include "dxc/HlslIntrinsicOp.h"

#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace hlsl;
Expand Down Expand Up @@ -418,6 +421,63 @@ struct IntrinsicLower {
DXIL::OpCode DxilOpcode;
};

void ConvertConstToInst(IRBuilder<> &Builder, ConstantExpr *const constVal) {
SmallSet<ConstantExpr *, 8> otherConsts;
for (User *const user : constVal->users()) {
if (ConstantExpr *const otherConst = dyn_cast<ConstantExpr>(user))
otherConsts.insert(otherConst);
}

for (ConstantExpr *const otherConst : otherConsts)
ConvertConstToInst(Builder, otherConst);

otherConsts.clear();

SmallVector<Value *, 8> users;

for (User *const user : constVal->users())
users.push_back(user);

for (Value *const user : users) {
Instruction *const inst = dyn_cast<Instruction>(user);
if (!inst)
continue;

// If the instruction is a phi node, we have to insert the new instructions
// in the correct predecessor.
if (PHINode *const phiNode = dyn_cast<PHINode>(inst)) {
const unsigned incomingValueCount = phiNode->getNumIncomingValues();
for (unsigned i = 0; i < incomingValueCount; i++) {
if (phiNode->getIncomingValue(i) == constVal) {
Builder.SetInsertPoint(phiNode->getIncomingBlock(i)->getTerminator());
break;
}
}
} else
Builder.SetInsertPoint(inst);

if (ConstantExpr *const constExpr = dyn_cast<ConstantExpr>(constVal)) {
Instruction *const insertPos =
Builder.Insert(constExpr->getAsInstruction());
inst->replaceUsesOfWith(constExpr, insertPos);
} else if (ConstantVector *const constVector =
dyn_cast<ConstantVector>(constVal)) {
Value *resultValue = UndefValue::get(constVector->getType());
for (unsigned i = 0; i < constVector->getNumOperands(); i++) {
// Have to not use the builder here because it will constant fold and we
// are trying to undo that now!
Instruction *const insertPos = InsertElementInst::Create(
resultValue, constVector->getOperand(i), Builder.getInt32(i));
resultValue = Builder.Insert(insertPos);
}
inst->replaceUsesOfWith(constVector, resultValue);
} else
llvm_unreachable("Should never be called!");
}

constVal->removeDeadConstantUsers();
}

// IOP intrinsics.
namespace {

Expand Down Expand Up @@ -2747,14 +2807,53 @@ Value *TranslatePow(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
return TranslatePowImpl(hlslOP, Builder, x, y, isFXCCompatMode);
}

Value *TranslatePrintf(CallInst *CI, IntrinsicOp IOP, DXIL::OpCode opcode,
Value *TranslatePrintf(CallInst *CI, IntrinsicOp IOP, OP::OpCode opcode,
HLOperationLowerHelper &helper,
HLObjectOperationLowerHelper *pObjHelper,
bool &Translated) {
Translated = false;
dxilutil::EmitErrorOnInstruction(CI,
"use of unsupported identifier 'printf'");
return nullptr;
Value *Op1 = CI->getArgOperand(1);
IRBuilder<> Builder(CI);
if (auto ConstantArg = dyn_cast<ConstantExpr>(Op1)) {
ConvertConstToInst(Builder, ConstantArg);
Op1 = CI->getArgOperand(1);
if (auto GemArg = dyn_cast<GetElementPtrInst>(Op1)) {
Op1 = GemArg->getPointerOperand();
}
}
assert(Op1->getType()->isPointerTy());
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Op1)) {
GV->setLinkage(GlobalValue::LinkageTypes::InternalLinkage);
}
auto hlslOP = &helper.hlslOP;
Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
SmallVector<Value *, 4> args = {opArg, Op1};
SmallVector<Type *, 4> argTypes = {Type::getVoidTy(CI->getContext()),
opArg->getType(), Op1->getType()};

std::string structName = "";
raw_string_ostream os(structName);
Op1->getType()->print(os);

for (unsigned i = 2; i < CI->getNumArgOperands(); ++i) {
auto arg = CI->getArgOperand(i);
args.push_back(arg);
argTypes.push_back(arg->getType());
os << ".";
arg->getType()->print(os);
}
os.flush();

Module *pModule = helper.M.GetModule();
Type *pTy = pModule->getTypeByName(structName);
Type *pOverloadedTy =
(pTy == nullptr)
? StructType::create(CI->getContext(), argTypes, structName)
: pTy;

Function *dxilFunc = hlslOP->GetOpFunc(opcode, pOverloadedTy, argTypes);

auto call = Builder.CreateCall(dxilFunc, args);
return call;
}

Value *TranslateFaceforward(CallInst *CI, IntrinsicOp IOP, OP::OpCode op,
Expand Down Expand Up @@ -6473,7 +6572,7 @@ IntrinsicLower gLowerTable[] = {
{IntrinsicOp::IOP_pack_s8, TranslatePack, DXIL::OpCode::Pack4x8},
{IntrinsicOp::IOP_pack_u8, TranslatePack, DXIL::OpCode::Pack4x8},
{IntrinsicOp::IOP_pow, TranslatePow, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_printf, TranslatePrintf, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_printf, TranslatePrintf, DXIL::OpCode::DebugPrintf},
{IntrinsicOp::IOP_radians, TranslateRadians, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_rcp, TranslateRCP, DXIL::OpCode::NumOpCodes},
{IntrinsicOp::IOP_reflect, TranslateReflect, DXIL::OpCode::NumOpCodes},
Expand Down
2 changes: 1 addition & 1 deletion tools/clang/test/CodeGenHLSL/printf.hlsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %dxc -E main -T vs_6_0 %s | FileCheck %s

// CHECK: use of unsupported identifier 'printf'
// CHECK: call void (i32, [20 x i8]*, i64, i64, i64, ...) @"dx.op.debugPrintf

float4 main(float4 p: Position) : SV_Position {

Expand Down
Loading

0 comments on commit a48593a

Please sign in to comment.