diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp index 301fe3d487565..1759b34af3e90 100644 --- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp @@ -178,14 +178,16 @@ void SPIRVPassConfig::addIRPasses() { TargetPassConfig::addIRPasses(); - addPass(createSPIRVRegularizerPass()); - addPass(createSPIRVPrepareFunctionsPass(TM)); - addPass(createSPIRVPrepareGlobalsPass()); - // Variadic function calls aren't supported in shader code. + // This needs to come before SPIRVPrepareFunctions because this + // may introduce intrinsic calls. if (!TM.getSubtargetImpl()->isShader()) { addPass(createExpandVariadicsPass(ExpandVariadicsMode::Lowering)); } + + addPass(createSPIRVRegularizerPass()); + addPass(createSPIRVPrepareFunctionsPass(TM)); + addPass(createSPIRVPrepareGlobalsPass()); } void SPIRVPassConfig::addISelPrepare() { diff --git a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp index a908db0d1830a..97b95cce2a407 100644 --- a/llvm/lib/Transforms/IPO/ExpandVariadics.cpp +++ b/llvm/lib/Transforms/IPO/ExpandVariadics.cpp @@ -53,6 +53,7 @@ #include "llvm/Transforms/IPO/ExpandVariadics.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" @@ -124,13 +125,16 @@ class VariadicABIInfo { }; virtual VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) = 0; - // Per-target overrides of special symbols. - virtual bool ignoreFunction(Function *F) { return false; } - // Targets implemented so far all have the same trivial lowering for these bool vaEndIsNop() { return true; } bool vaCopyIsMemcpy() { return true; } + // Any additional address spaces used in va intrinsics that should be + // expanded. + virtual SmallVector getTargetSpecificVaIntrinAddrSpaces() const { + return {}; + } + virtual ~VariadicABIInfo() = default; }; @@ -238,9 +242,6 @@ class ExpandVariadics : public ModulePass { F->hasFnAttribute(Attribute::Naked)) return false; - if (ABI->ignoreFunction(F)) - return false; - if (!isValidCallingConv(F)) return false; @@ -364,13 +365,21 @@ bool ExpandVariadics::runOnModule(Module &M) { // variadic functions have also been replaced. { - // 0 and AllocaAddrSpace are sufficient for the targets implemented so far unsigned Addrspace = 0; Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace); Addrspace = DL.getAllocaAddrSpace(); if (Addrspace != 0) Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace); + + // Process any addrspaces targets declare to be important. + const SmallVector &TargetASVec = + ABI->getTargetSpecificVaIntrinAddrSpaces(); + for (unsigned TargetAS : TargetASVec) { + if (TargetAS == 0 || TargetAS == DL.getAllocaAddrSpace()) + continue; + Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, TargetAS); + } } if (Mode != ExpandVariadicsMode::Lowering) @@ -618,9 +627,6 @@ bool ExpandVariadics::expandCall(Module &M, IRBuilder<> &Builder, CallBase *CB, bool Changed = false; const DataLayout &DL = M.getDataLayout(); - if (ABI->ignoreFunction(CB->getCalledFunction())) - return Changed; - if (!expansionApplicableToFunctionCall(CB)) { if (rewriteABI()) report_fatal_error("Cannot lower callbase instruction"); @@ -978,10 +984,9 @@ struct SPIRV final : public VariadicABIInfo { return {A, false}; } - // The SPIR-V backend has special handling for SPIR-V mangled printf - // functions. - bool ignoreFunction(Function *F) override { - return F->getName().starts_with('_') && F->getName().contains("printf"); + // We will likely see va intrinsics in the generic addrspace (4). + SmallVector getTargetSpecificVaIntrinAddrSpaces() const override { + return {4}; } }; @@ -1041,6 +1046,7 @@ std::unique_ptr VariadicABIInfo::create(const Triple &T) { } case Triple::spirv: + case Triple::spirv32: case Triple::spirv64: { return std::make_unique(); } diff --git a/llvm/test/CodeGen/SPIRV/function/variadics-lowering-namespace-printf.ll b/llvm/test/CodeGen/SPIRV/function/variadics-lowering-namespace-printf.ll new file mode 100644 index 0000000000000..6e2fda6a7e5eb --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/function/variadics-lowering-namespace-printf.ll @@ -0,0 +1,41 @@ +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers < %s 2>&1 | FileCheck %s + +; CHECK: OpName [[MAIN:%.*]] "main" +; CHECK: [[MAIN]] = OpFunction +; CHECK-NOT: OPFunctionEnd +; CHECK: OpLifetimeStart +; CHECK-NOT: OPFunctionEnd +; CHECK: OpLifetimeStop +; CHECK: OpFunctionEnd + +@.str = private unnamed_addr addrspace(1) constant [3 x i8] c"%s\00", align 1 +@.str.1 = private unnamed_addr addrspace(1) constant [4 x i8] c"hey\00", align 1 + +declare spir_func noundef i32 @_Z7vprintfPKcz(ptr addrspace(4) noundef %0, ...) addrspace(9) + +define spir_func noundef i32 @_ZN4ompx6printfEPKcz(ptr addrspace(4) noundef %Format, ...) addrspace(9) { +entry: + %retval = alloca i32, align 4 + %Format.addr = alloca ptr addrspace(4), align 8 + %vlist = alloca ptr addrspace(4), align 8 + %retval.ascast = addrspacecast ptr %retval to ptr addrspace(4) + %Format.addr.ascast = addrspacecast ptr %Format.addr to ptr addrspace(4) + %vlist.ascast = addrspacecast ptr %vlist to ptr addrspace(4) + store ptr addrspace(4) %Format, ptr addrspace(4) %Format.addr.ascast, align 8 + call addrspace(9) void @llvm.va_start.p4(ptr addrspace(4) %vlist.ascast) + %0 = load ptr addrspace(4), ptr addrspace(4) %Format.addr.ascast, align 8 + %1 = load ptr addrspace(4), ptr addrspace(4) %vlist.ascast, align 8 + %call = call spir_func noundef addrspace(9) i32 (ptr addrspace(4), ...) @_Z7vprintfPKcz(ptr addrspace(4) noundef %0, ptr addrspace(4) noundef %1) + ret i32 %call +} + +declare void @llvm.va_start.p4(ptr addrspace(4)) addrspace(9) + +define noundef i32 @main() addrspace(9) { +entry: + %retval = alloca i32, align 4 + %retval.ascast = addrspacecast ptr %retval to ptr addrspace(4) + store i32 0, ptr addrspace(4) %retval.ascast, align 4 + %call = call spir_func noundef addrspace(9) i32 (ptr addrspace(4), ...) @_ZN4ompx6printfEPKcz(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @.str to ptr addrspace(4)), ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) @.str.1 to ptr addrspace(4))) #5 + ret i32 0 +} diff --git a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll index 70ae7081ad5d5..a4fcd9e6d9223 100644 --- a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll +++ b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll @@ -31,10 +31,11 @@ ; SPIRV-O0-NEXT: Instrument function entry/exit with calls to e.g. mcount() (post inlining) ; SPIRV-O0-NEXT: Scalarize Masked Memory Intrinsics ; SPIRV-O0-NEXT: Expand reduction intrinsics +; SPIRV-O0-NEXT: Expand variadic functions +; SPIRV-O0-NEXT: FunctionPass Manager ; SPIRV-O0-NEXT: SPIR-V Regularizer ; SPIRV-O0-NEXT: SPIRV prepare functions ; SPIRV-O0-NEXT: SPIRV prepare global variables -; SPIRV-O0-NEXT: Expand variadic functions ; SPIRV-O0-NEXT: FunctionPass Manager ; SPIRV-O0-NEXT: Lower invoke and unwind, for unwindless code generators ; SPIRV-O0-NEXT: Remove unreachable blocks from the CFG @@ -136,10 +137,11 @@ ; SPIRV-Opt-NEXT: Instrument function entry/exit with calls to e.g. mcount() (post inlining) ; SPIRV-Opt-NEXT: Scalarize Masked Memory Intrinsics ; SPIRV-Opt-NEXT: Expand reduction intrinsics +; SPIRV-Opt-NEXT: Expand variadic functions +; SPIRV-Opt-NEXT: FunctionPass Manager ; SPIRV-Opt-NEXT: SPIR-V Regularizer ; SPIRV-Opt-NEXT: SPIRV prepare functions ; SPIRV-Opt-NEXT: SPIRV prepare global variables -; SPIRV-Opt-NEXT: Expand variadic functions ; SPIRV-Opt-NEXT: FunctionPass Manager ; SPIRV-Opt-NEXT: Dominator Tree Construction ; SPIRV-Opt-NEXT: Natural Loop Information diff --git a/llvm/test/CodeGen/SPIRV/printf.ll b/llvm/test/CodeGen/SPIRV/printf.ll index 483fc1f244e57..f2747901c54e0 100644 --- a/llvm/test/CodeGen/SPIRV/printf.ll +++ b/llvm/test/CodeGen/SPIRV/printf.ll @@ -6,33 +6,35 @@ ; CHECK: %[[#ExtImport:]] = OpExtInstImport "OpenCL.std" ; CHECK: %[[#Char:]] = OpTypeInt 8 0 -; CHECK: %[[#CharPtr:]] = OpTypePointer UniformConstant %[[#Char]] +; CHECK: %[[#ConstCharPtr:]] = OpTypePointer UniformConstant %[[#Char]] +; CHECK: %[[#VarargStruct:]] = OpTypeStruct %[[#Char]] +; CHECK: %[[#VarargStructPtr:]] = OpTypePointer Function %[[#VarargStruct]] +; CHECK: %[[#CharPtr:]] = OpTypePointer Function %[[#Char]] +; CHECK: %[[#IntConst:]] = OpConstant %[[#Char]] 97 ; CHECK: %[[#GV:]] = OpVariable %[[#]] UniformConstant %[[#]] ; CHECK: OpFunction -; CHECK: %[[#Arg1:]] = OpFunctionParameter -; CHECK: %[[#Arg2:]] = OpFunctionParameter -; CHECK: %[[#CastedGV:]] = OpBitcast %[[#CharPtr]] %[[#GV]] -; CHECK-NEXT: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#CastedGV]] %[[#ArgConst:]] -; CHECK-NEXT: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#CastedGV]] %[[#ArgConst]] -; CHECK-NEXT: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#Arg1]] %[[#ArgConst:]] -; CHECK-NEXT: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#Arg1]] %[[#ArgConst]] -; CHECK-NEXT: %[[#CastedArg2:]] = OpBitcast %[[#CharPtr]] %[[#Arg2]] -; CHECK-NEXT: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#CastedArg2]] %[[#ArgConst]] -; CHECK-NEXT: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#CastedArg2]] %[[#ArgConst]] +; CHECK: %[[#Arg:]] = OpFunctionParameter +; CHECK: %[[#VarargBuffer1:]] = OpVariable %[[#VarargStructPtr]] Function +; CHECK: %[[#VarargBuffer2:]] = OpVariable %[[#VarargStructPtr]] Function +; CHECK: %[[#CastedBuffer1:]] = OpBitcast %[[#CharPtr]] %[[#VarargBuffer1]] +; CHECK: %[[#GEP1:]] = OpInBoundsPtrAccessChain %[[#CharPtr]] %[[#VarargBuffer1]] +; CHECK: OpStore %[[#GEP1]] %[[#IntConst]] Aligned 1 +; CHECK: %[[#CastedGV:]] = OpBitcast %[[#ConstCharPtr]] %[[#GV]] +; CHECK: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#CastedGV]] %[[#CastedBuffer1:]] +; CHECK: %[[#CastedBuffer2:]] = OpBitcast %[[#CharPtr]] %[[#VarargBuffer2]] +; CHECK: %[[#GEP2:]] = OpInBoundsPtrAccessChain %[[#CharPtr]] %[[#VarargBuffer2]] +; CHECK: OpStore %[[#GEP2]] %[[#IntConst]] Aligned 1 +; CHECK: OpExtInst %[[#]] %[[#ExtImport]] printf %[[#Arg]] %[[#CastedBuffer2:]] ; CHECK: OpFunctionEnd %struct = type { [6 x i8] } @FmtStr = internal addrspace(2) constant [6 x i8] c"c=%c\0A\00", align 1 -define spir_kernel void @foo(ptr addrspace(2) %_arg_fmt1, ptr addrspace(2) byval(%struct) %_arg_fmt2) { +define spir_kernel void @foo(ptr addrspace(2) %_arg_fmt) { entry: %r1 = tail call spir_func i32 (ptr addrspace(2), ...) @_Z6printfPU3AS2Kcz(ptr addrspace(2) @FmtStr, i8 signext 97) - %r2 = tail call spir_func i32 (ptr addrspace(2), ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2) @FmtStr, i8 signext 97) - %r3 = tail call spir_func i32 (ptr addrspace(2), ...) @_Z6printfPU3AS2Kcz(ptr addrspace(2) %_arg_fmt1, i8 signext 97) - %r4 = tail call spir_func i32 (ptr addrspace(2), ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2) %_arg_fmt1, i8 signext 97) - %r5 = tail call spir_func i32 (ptr addrspace(2), ...) @_Z6printfPU3AS2Kcz(ptr addrspace(2) %_arg_fmt2, i8 signext 97) - %r6 = tail call spir_func i32 (ptr addrspace(2), ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2) %_arg_fmt2, i8 signext 97) + %r2 = tail call spir_func i32 (ptr addrspace(2), ...) @_Z18__spirv_ocl_printfPU3AS2Kcz(ptr addrspace(2) %_arg_fmt, i8 signext 97) ret void }