[clang] [llvm] [AVR] Fix Avr indvar detection and strength reduction (missed optimization) (PR #152028)
Tom Vijlbrief via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 4 13:42:05 PDT 2025
https://github.com/tomtor updated https://github.com/llvm/llvm-project/pull/152028
>From c5206367a672d52b6761490b144e0221f8dafcf3 Mon Sep 17 00:00:00 2001
From: Tom Vijlbrief <tvijlbrief at gmail.com>
Date: Sun, 3 Aug 2025 09:15:58 +0200
Subject: [PATCH 1/3] Improve AVR loop code generation
---
clang/lib/Basic/Targets/AVR.h | 3 +-
llvm/lib/Target/AVR/AVRTargetMachine.cpp | 11 ++-
llvm/lib/Target/AVR/AVRTargetMachine.h | 2 +
llvm/lib/Target/AVR/AVRTargetTransformInfo.h | 79 ++++++++++++++++++++
4 files changed, 92 insertions(+), 3 deletions(-)
create mode 100644 llvm/lib/Target/AVR/AVRTargetTransformInfo.h
diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h
index 75c969fd59dc9..11aa844f2ce55 100644
--- a/clang/lib/Basic/Targets/AVR.h
+++ b/clang/lib/Basic/Targets/AVR.h
@@ -57,7 +57,8 @@ class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo {
Int16Type = SignedInt;
Char32Type = UnsignedLong;
SigAtomicType = SignedChar;
- resetDataLayout("e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8");
+ resetDataLayout(
+ "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-n16:8-a:8");
}
void getTargetDefines(const LangOptions &Opts,
diff --git a/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
index b75417a0896a5..8d05005e287f4 100644
--- a/llvm/lib/Target/AVR/AVRTargetMachine.cpp
+++ b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
@@ -19,6 +19,7 @@
#include "AVR.h"
#include "AVRMachineFunctionInfo.h"
+#include "AVRTargetTransformInfo.h"
#include "AVRTargetObjectFile.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
#include "TargetInfo/AVRTargetInfo.h"
@@ -28,7 +29,7 @@
namespace llvm {
static const char *AVRDataLayout =
- "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8";
+ "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-n16:8-a:8";
/// Processes a CPU name.
static StringRef getCPU(StringRef CPU) {
@@ -62,7 +63,9 @@ namespace {
class AVRPassConfig : public TargetPassConfig {
public:
AVRPassConfig(AVRTargetMachine &TM, PassManagerBase &PM)
- : TargetPassConfig(TM, PM) {}
+ : TargetPassConfig(TM, PM) {
+ EnableLoopTermFold = true;
+ }
AVRTargetMachine &getAVRTargetMachine() const {
return getTM<AVRTargetMachine>();
@@ -107,6 +110,10 @@ const AVRSubtarget *AVRTargetMachine::getSubtargetImpl(const Function &) const {
return &SubTarget;
}
+TargetTransformInfo AVRTargetMachine::getTargetTransformInfo(const Function &F) const {
+ return TargetTransformInfo(std::make_unique<AVRTTIImpl>(this, F));
+}
+
MachineFunctionInfo *AVRTargetMachine::createMachineFunctionInfo(
BumpPtrAllocator &Allocator, const Function &F,
const TargetSubtargetInfo *STI) const {
diff --git a/llvm/lib/Target/AVR/AVRTargetMachine.h b/llvm/lib/Target/AVR/AVRTargetMachine.h
index 167d0076e9581..9452b3d8cd8a5 100644
--- a/llvm/lib/Target/AVR/AVRTargetMachine.h
+++ b/llvm/lib/Target/AVR/AVRTargetMachine.h
@@ -48,6 +48,8 @@ class AVRTargetMachine : public CodeGenTargetMachineImpl {
createMachineFunctionInfo(BumpPtrAllocator &Allocator, const Function &F,
const TargetSubtargetInfo *STI) const override;
+ TargetTransformInfo getTargetTransformInfo(const Function &F) const override;
+
bool isNoopAddrSpaceCast(unsigned SrcAs, unsigned DestAs) const override {
// While AVR has different address spaces, they are all represented by
// 16-bit pointers that can be freely casted between (of course, a pointer
diff --git a/llvm/lib/Target/AVR/AVRTargetTransformInfo.h b/llvm/lib/Target/AVR/AVRTargetTransformInfo.h
new file mode 100644
index 0000000000000..e1abd10619823
--- /dev/null
+++ b/llvm/lib/Target/AVR/AVRTargetTransformInfo.h
@@ -0,0 +1,79 @@
+//===- AVRTargetTransformInfo.h - AVR specific TTI ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file defines a TargetTransformInfoImplBase conforming object specific
+/// to the AVR target machine. It uses the target's detailed information to
+/// provide more precise answers to certain TTI queries, while letting the
+/// target independent and default TTI implementations handle the rest.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_AVR_AVRTARGETTRANSFORMINFO_H
+#define LLVM_LIB_TARGET_AVR_AVRTARGETTRANSFORMINFO_H
+
+#include "AVRSubtarget.h"
+#include "AVRTargetMachine.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/CodeGen/BasicTTIImpl.h"
+#include "llvm/IR/Function.h"
+#include <optional>
+
+namespace llvm {
+
+class AVRTTIImpl final : public BasicTTIImplBase<AVRTTIImpl> {
+ using BaseT = BasicTTIImplBase<AVRTTIImpl>;
+ using TTI = TargetTransformInfo;
+
+ friend BaseT;
+
+ const AVRSubtarget *ST;
+ const AVRTargetLowering *TLI;
+
+ const AVRSubtarget *getST() const { return ST; }
+ const AVRTargetLowering *getTLI() const { return TLI; }
+
+public:
+ explicit AVRTTIImpl(const AVRTargetMachine *TM, const Function &F)
+ : BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
+ TLI(ST->getTargetLowering()) {}
+
+#if 0 // TODO Examine if these options result in better code generation
+ /// Return the cost of materializing an immediate for a value operand of
+ /// a store instruction.
+ InstructionCost getStoreImmCost(Type *VecTy, TTI::OperandValueInfo OpInfo,
+ TTI::TargetCostKind CostKind) const;
+
+ InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
+ TTI::TargetCostKind CostKind) const override;
+ InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
+ const APInt &Imm, Type *Ty,
+ TTI::TargetCostKind CostKind,
+ Instruction *Inst = nullptr) const override;
+ InstructionCost
+ getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
+ Type *Ty, TTI::TargetCostKind CostKind) const override;
+
+ InstructionCost
+ getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
+ TTI::TargetCostKind CostKind) const override;
+
+ InstructionCost getCmpSelInstrCost(
+ unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,
+ TTI::TargetCostKind CostKind,
+ TTI::OperandValueInfo Op1Info = {TTI::OK_AnyValue, TTI::OP_None},
+ TTI::OperandValueInfo Op2Info = {TTI::OK_AnyValue, TTI::OP_None},
+ const Instruction *I = nullptr) const override;
+#endif
+
+ bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
+ const TargetTransformInfo::LSRCost &C2) const override {return C1.Insns < C2.Insns;}
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_TARGET_AVR_AVRTARGETTRANSFORMINFO_H
>From 68222e983264aa5eb50ab4e655ab260da75ed8e2 Mon Sep 17 00:00:00 2001
From: Tom Vijlbrief <tvijlbrief at gmail.com>
Date: Mon, 4 Aug 2025 22:25:00 +0200
Subject: [PATCH 2/3] handle pre/post and complete tests
---
llvm/lib/Target/AVR/AVRTargetTransformInfo.h | 49 ++++++++------------
llvm/test/CodeGen/AVR/bug-143247.ll | 4 +-
llvm/test/CodeGen/AVR/load.ll | 34 +++++++-------
llvm/test/CodeGen/AVR/shift.ll | 2 +-
4 files changed, 39 insertions(+), 50 deletions(-)
diff --git a/llvm/lib/Target/AVR/AVRTargetTransformInfo.h b/llvm/lib/Target/AVR/AVRTargetTransformInfo.h
index e1abd10619823..b877918a18151 100644
--- a/llvm/lib/Target/AVR/AVRTargetTransformInfo.h
+++ b/llvm/lib/Target/AVR/AVRTargetTransformInfo.h
@@ -33,6 +33,7 @@ class AVRTTIImpl final : public BasicTTIImplBase<AVRTTIImpl> {
const AVRSubtarget *ST;
const AVRTargetLowering *TLI;
+ const Function *currentF;
const AVRSubtarget *getST() const { return ST; }
const AVRTargetLowering *getTLI() const { return TLI; }
@@ -40,38 +41,26 @@ class AVRTTIImpl final : public BasicTTIImplBase<AVRTTIImpl> {
public:
explicit AVRTTIImpl(const AVRTargetMachine *TM, const Function &F)
: BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
- TLI(ST->getTargetLowering()) {}
-
-#if 0 // TODO Examine if these options result in better code generation
- /// Return the cost of materializing an immediate for a value operand of
- /// a store instruction.
- InstructionCost getStoreImmCost(Type *VecTy, TTI::OperandValueInfo OpInfo,
- TTI::TargetCostKind CostKind) const;
-
- InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
- TTI::TargetCostKind CostKind) const override;
- InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
- const APInt &Imm, Type *Ty,
- TTI::TargetCostKind CostKind,
- Instruction *Inst = nullptr) const override;
- InstructionCost
- getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
- Type *Ty, TTI::TargetCostKind CostKind) const override;
-
- InstructionCost
- getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
- TTI::TargetCostKind CostKind) const override;
-
- InstructionCost getCmpSelInstrCost(
- unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,
- TTI::TargetCostKind CostKind,
- TTI::OperandValueInfo Op1Info = {TTI::OK_AnyValue, TTI::OP_None},
- TTI::OperandValueInfo Op2Info = {TTI::OK_AnyValue, TTI::OP_None},
- const Instruction *I = nullptr) const override;
-#endif
+ TLI(ST->getTargetLowering()), currentF(&F) {}
bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
- const TargetTransformInfo::LSRCost &C2) const override {return C1.Insns < C2.Insns;}
+ const TargetTransformInfo::LSRCost &C2) const override {
+ // Detect %incdec.ptr because loop-reduce loses them
+ for (const BasicBlock &BB : *currentF) {
+ if (BB.getName().find("while.body") != std::string::npos) {
+ for (const Instruction &I : BB) {
+ std::string str;
+ llvm::raw_string_ostream(str) << I;
+ if (str.find("%incdec.ptr") != std::string::npos)
+ return false;
+ }
+ }
+ }
+ if (C2.Insns == ~0u)
+ return true;
+ return 2 * C1.Insns + C1.AddRecCost + C1.SetupCost + C1.NumRegs <
+ 2 * C2.Insns + C2.AddRecCost + C2.SetupCost + C2.NumRegs;
+ }
};
} // end namespace llvm
diff --git a/llvm/test/CodeGen/AVR/bug-143247.ll b/llvm/test/CodeGen/AVR/bug-143247.ll
index 07c4c6562c950..d4493272af76d 100644
--- a/llvm/test/CodeGen/AVR/bug-143247.ll
+++ b/llvm/test/CodeGen/AVR/bug-143247.ll
@@ -8,18 +8,18 @@ define void @complex_sbi() {
; CHECK: ; %bb.0: ; %entry
; CHECK-NEXT: push r16
; CHECK-NEXT: push r17
-; CHECK-NEXT: ldi r24, 0
+; CHECK-NEXT: ldi r24, 1
; CHECK-NEXT: ldi r25, 0
; CHECK-NEXT: .LBB0_1: ; %while.cond
; CHECK-NEXT: ; =>This Inner Loop Header: Depth=1
; CHECK-NEXT: sbi 1, 7
-; CHECK-NEXT: adiw r24, 1
; CHECK-NEXT: movw r16, r24
; CHECK-NEXT: andi r24, 15
; CHECK-NEXT: andi r25, 0
; CHECK-NEXT: adiw r24, 1
; CHECK-NEXT: call nil
; CHECK-NEXT: movw r24, r16
+; CHECK-NEXT: adiw r24, 1
; CHECK-NEXT: rjmp .LBB0_1
entry:
br label %while.cond
diff --git a/llvm/test/CodeGen/AVR/load.ll b/llvm/test/CodeGen/AVR/load.ll
index 5de6b48652914..e2e7844b49c02 100644
--- a/llvm/test/CodeGen/AVR/load.ll
+++ b/llvm/test/CodeGen/AVR/load.ll
@@ -1,4 +1,4 @@
-; RUN: llc -mattr=avr6,sram < %s -mtriple=avr -verify-machineinstrs | FileCheck %s
+; RUN: llc -mattr=avr6,sram < %s -mtriple=avr-none -verify-machineinstrs | FileCheck %s
define i8 @load8(ptr %x) {
; CHECK-LABEL: load8:
@@ -76,26 +76,26 @@ while.end: ; preds = %while.body, %entry
ret i8 %r.0.lcssa
}
-define i16 @load16postinc(ptr %x, i16 %y) {
+define i16 @load16postinc(ptr %p, i16 %cnt) {
; CHECK-LABEL: load16postinc:
; CHECK: ld {{.*}}, {{[XYZ]}}+
; CHECK: ld {{.*}}, {{[XYZ]}}+
entry:
- %tobool2 = icmp eq i16 %y, 0
- br i1 %tobool2, label %while.end, label %while.body
-while.body: ; preds = %entry, %while.body
- %r.05 = phi i16 [ %add, %while.body ], [ 0, %entry ]
- %y.addr.04 = phi i16 [ %dec, %while.body ], [ %y, %entry ]
- %x.addr.03 = phi ptr [ %incdec.ptr, %while.body ], [ %x, %entry ]
- %dec = add nsw i16 %y.addr.04, -1
- %incdec.ptr = getelementptr inbounds i16, ptr %x.addr.03, i16 1
- %0 = load i16, ptr %x.addr.03
- %add = add nsw i16 %0, %r.05
- %tobool = icmp eq i16 %dec, 0
- br i1 %tobool, label %while.end, label %while.body
-while.end: ; preds = %while.body, %entry
- %r.0.lcssa = phi i16 [ 0, %entry ], [ %add, %while.body ]
- ret i16 %r.0.lcssa
+ %cmp3 = icmp sgt i16 %cnt, 0
+ br i1 %cmp3, label %for.body, label %for.cond.cleanup
+for.cond.cleanup: ; preds = %for.body, %entry
+ %sum.0.lcssa = phi i16 [ 0, %entry ], [ %add, %for.body ]
+ ret i16 %sum.0.lcssa
+for.body: ; preds = %entry, %for.body
+ %i.06 = phi i16 [ %inc, %for.body ], [ 0, %entry ]
+ %sum.05 = phi i16 [ %add, %for.body ], [ 0, %entry ]
+ %p.addr.04 = phi ptr [ %incdec.ptr, %for.body ], [ %p, %entry ]
+ %incdec.ptr = getelementptr inbounds nuw i8, ptr %p.addr.04, i16 2
+ %0 = load i16, ptr %p.addr.04, align 1
+ %add = add nsw i16 %0, %sum.05
+ %inc = add nuw nsw i16 %i.06, 1
+ %exitcond.not = icmp eq i16 %inc, %cnt
+ br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}
define i8 @load8predec(ptr %x, i8 %y) {
diff --git a/llvm/test/CodeGen/AVR/shift.ll b/llvm/test/CodeGen/AVR/shift.ll
index 9836f93527b3c..1bd9b45999d7b 100644
--- a/llvm/test/CodeGen/AVR/shift.ll
+++ b/llvm/test/CodeGen/AVR/shift.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=avr -mtriple=avr -verify-machineinstrs | FileCheck %s
+; RUN: llc < %s -mtriple=avr-none -verify-machineinstrs | FileCheck %s
; Optimize for speed.
define i8 @shift_i8_i8_speed(i8 %a, i8 %b) {
>From 38ca2245d0747deb8752f8495187e54cfefc8a8d Mon Sep 17 00:00:00 2001
From: Tom Vijlbrief <tvijlbrief at gmail.com>
Date: Mon, 4 Aug 2025 22:39:46 +0200
Subject: [PATCH 3/3] formatting
---
llvm/lib/Target/AVR/AVRTargetMachine.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
index 8d05005e287f4..02212d2151f4c 100644
--- a/llvm/lib/Target/AVR/AVRTargetMachine.cpp
+++ b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
@@ -19,8 +19,8 @@
#include "AVR.h"
#include "AVRMachineFunctionInfo.h"
-#include "AVRTargetTransformInfo.h"
#include "AVRTargetObjectFile.h"
+#include "AVRTargetTransformInfo.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"
#include "TargetInfo/AVRTargetInfo.h"
@@ -110,7 +110,8 @@ const AVRSubtarget *AVRTargetMachine::getSubtargetImpl(const Function &) const {
return &SubTarget;
}
-TargetTransformInfo AVRTargetMachine::getTargetTransformInfo(const Function &F) const {
+TargetTransformInfo
+AVRTargetMachine::getTargetTransformInfo(const Function &F) const {
return TargetTransformInfo(std::make_unique<AVRTTIImpl>(this, F));
}
More information about the llvm-commits
mailing list